Pen SDK Programming Guide
Pen SDK Programming Guide
Programming Guide
Version 4.1.2
2. HELLOPEN ......................................................................................................................................................... 11
Pen SDK provides functions for verifying if the Spen is activated, identifying event coordinates, sensing the
pressure, verifying if the side button is pressed, processing hover events and more for your application.
The SpenSurfaceView class, which inherits from Android SurfaceView, processes finger and S pen inputs to
express data on the viewport. Pen SDK saves the objects drawn on an SpenSurfaceView instance in
SpenPageDoc, with multiple SpenPageDocs making an SpenNoteDoc file.
The following figure shows the relationship between SpenPageDoc and SpenSurfaceView.
1.2. Architecture
The following figure shows the Pen SDK architecture.
Processing S pen touch events and hover events, sensing S pen pressure and checking if the side
button is pressed.
Processing handwritten input with a finger or a S pen and converting it to text or a vector image.
Zoom in and out and pan on the viewport.
Managing user preferences for pens, erasers, and text.
Managing input objects and maintaining their states.
Selecting, scaling, moving, rotating, grouping, and ungrouping objects.
Managing the history of an input object.
Adding third party templates and runtime objects.
1.6. Components
Components
o pen-v4.1.x.aar
o sdk-v1.0.0.jar
Imported Pen SDK:
o com.samsung.android.sdk.pen
repositories {
flatDir {
dirs 'libs'
}
}
dependencies {
compile files('libs/sdk-v1.0.0.jar')
compile(name:'pen-v4.1.2_full', ext:'aar');
}
Add the following permission to your Android manifest file to access the Pen SDK external storage.
<uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Add the following permission to your Android manifest file to access the camera from methods such as
SpenSurfaceView.takeStrokeFrame() and SpenSurfaceView.retakeStrokeFrame() .
<uses-permissionandroid:name="android.permission.CAMERA"/>
Select Android 4.0 (Ice Cream Sandwich) or higher as a Project Build Target in your project properties.
The following permission has to be specified in the AndroidManifest.xml fileto initialize Pen SDK.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_hello_pen);
mContext = this;
// Initialize Pen.
boolean isSpenFeatureEnabled = false;
Spen spenPackage = new Spen();
try {
spenPackage.initialize(this);
isSpenFeatureEnabled =
spenPackage.isFeatureEnabled(Spen.DEVICE_PEN);
} catch (SsdkUnsupportedException e) {
Toast.makeText(mContext, "This device does not support Spen.",
Toast.LENGTH_SHORT).show();
e.printStackTrace();
finish();
} catch (Exception e1) {
Toast.makeText(mContext, "Cannot initialize Pen.",
Toast.LENGTH_SHORT).show();
e1.printStackTrace();
finish();
}
if(isSpenFeatureEnabled == false) {
mSpenSurfaceView.setToolTypeAction(SpenSurfaceView.TOOL_FINGER,
SpenSurfaceView.ACTION_STROKE);
Toast.makeText(mContext,
"Device does not support Spen. \n You can draw stroke by finger.",
Toast.LENGTH_SHORT).show();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if(mSpenSurfaceView != null) {
mSpenSurfaceView.close();
mSpenSurfaceView = null;
}
if(mSpenNoteDoc != null) {
try {
mSpenNoteDoc.close();
} catch (Exception e) {
e.printStackTrace();
}
mSpenNoteDoc = null;
}
};
}
initialize() initializes Pen SDK. You need to initialize Pen SDK before you can use it. If the device
does not support S Pen, SsdkUnsupportedException is thrown.
getVersionCode() returns the PenSDK version number as an integer.
If initializing Pen SDK is failed, the initialize() method throws an SsdkUnsupportedException exception.
To find out the reason for the exception, check the exception message.
The following five types of exception messages are defined in the Spen class:
1. Call Spen.isFeatureEnabled(Spen.DEVICE_PEN) .
if(spenPackage.isFeatureEnabled(Spen.DEVICE_PEN) == false) {
mSpenSurfaceView.setToolTypeAction(SpenSurfaceView.TOOL_FINGER,
SpenSurfaceView.ACTION_STROKE);
Toast.makeText(mContext,
"Device does not support S pen. \n You can draw strokeswith yourfinger",
In this case, the application has to call initialize method with isForce32BitMode = true.
Note
Pen SDK libraries including 32/64bit .so files. In this case 64 bit .so files is unnecessary. For saving
memory of application, modify build.gradle file in Android Studio as below:
packagingOptions {
exclude 'lib/arm64-v8a/libgnustl_shared.so'
exclude 'lib/arm64-v8a/libSPenBase.so'
exclude 'lib/arm64-v8a/libSPenBeautify.so'
exclude 'lib/arm64-v8a/libSPenBrush.so'
exclude 'lib/arm64-v8a/libSPenChineseBrush.so'
exclude 'lib/arm64-v8a/libSPenEngine.so'
exclude 'lib/arm64-v8a/libSPenFountainPen.so'
SpenSurfaceView and SpenSettingPenLayout combine to provide methods for managing user preferences
for font, font size, and font color; the size, color, or type of the pen tool; the size of the eraser tool; and
options for objects.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_hello_pen);
mContext = this;
// Initialize Pen.
boolean isSpenFeatureEnabled = false;
Spen spenPackage = new Spen();
try {
spenPackage.initialize(this);
isSpenFeatureEnabled =
spenPackage.isFeatureEnabled(Spen.DEVICE_PEN);
} catch (SsdkUnsupportedException e) {
if( processUnsupportedException(e) == true) {
return;
}
} catch (Exception e1) {
Toast.makeText(mContext, "Cannot initialize Pen.",
Toast.LENGTH_SHORT).show();
e1.printStackTrace();
finish();
}
// Create a PenView.
RelativeLayout spenViewLayout =
(RelativeLayout) findViewById(R.id.spenViewLayout);
mSpenSurfaceView = new SpenSurfaceView(mContext);
if (mSpenSurfaceView == null) {
Toast.makeText(mContext, "Cannot create new SpenSurfaceView.",
Toast.LENGTH_SHORT).show();
finish();
}
spenViewLayout.addView(mSpenSurfaceView);
if(isSpenFeatureEnabled == false) {
mSpenSurfaceView.setToolTypeAction(SpenSurfaceView.TOOL_FINGER,
SpenSurfaceView.ACTION_STROKE);
Toast.makeText(mContext,
"Device does not support S pen. \n You can draw strokeswith your finger",
Toast.LENGTH_SHORT).show();
}
}
e.printStackTrace();
int errorType = e.getType();
// The device is not a Samsung device or it is a Samsung device that does not
support S pen.
if(errorType == SsdkUnsupportedException.VENDOR_NOT_SUPPORTED ||
errorType == SsdkUnsupportedException.DEVICE_NOT_SUPPORTED ) {
Toast.makeText(mContext, "This device does not support Spen.",
Toast.LENGTH_SHORT).show();
finish();
} else if(errorType == SsdkUnsupportedException.LIBRARY_NOT_INSTALLED) {
// SpenSdk 4.1 apk is not installed on the device.
showAlertDialog( "You need to install an additional package"
+ " to use this application."
+ "You will be taken to the installation screen."
+ "Restart this application after the software has been installed."
, true);
} else if(errorType ==
SsdkUnsupportedException.LIBRARY_UPDATE_IS_REQUIRED) {
// The Pen library or SpenSdk 4.1 apk requires to be updated.
showAlertDialog("You need to update the installed Pen library or package"
+ "to use this application."
+ " You will be taken to the installation screen."
+ " Restart this application after the software has been updated."
, true);
} else if(errorType ==
SsdkUnsupportedException.LIBRARY_UPDATE_IS_RECOMMENDED) {
// It is recommended that the Pen library or SpenSdk 4.1 apk is updated to
// thelatest version as possible.
showAlertDialog("We recommend that you update the installed Pen library or
package"
+ " before using this application."
+ " You will be taken to the installation screen."
+ " Restart this application after the software has been updated."
, false);
return false;
}
return true;
}
dialog.dismiss();
finish();
}
})
.setNegativeButton(android.R.string.no,
new DialogInterface.OnClickListener() {
@Override
public void onClick(
DialogInterface dialog, int which) {
if(closeActivity == true) {
// Terminate the activity if the user does not wish to install and closes the
dialog.
finish();
}
dialog.dismiss();
}
}).show();
dlg = null;
}
@Override
protected void onDestroy() {
super.onDestroy();
if(mSpenSurfaceView != null) {
mSpenSurfaceView.close();
mSpenSurfaceView = null;
}
if(mSpenNoteDoc != null) {
try {
mSpenNoteDoc.close();
} catch (Exception e) {
e.printStackTrace();
}
mSpenNoteDoc = null;
}
};
}
The following sections provide more details on the steps involved in drawing on the screen.
Pen SDK runs only on Samsung devices. The Spen.initialize() method throws an
SsdkUnsupportedException exception on other devices. Handle the SsdkUnsupportedException exception
as shown in the sample code below.
If the device is not a Samsung device or if the device is a Samsung device that does not support S pen:
Display a message that the device does not support Pen SDK.
Call finish() to close the application.
If SpenSdk 4.1 apk is not installed or if it is not the latest version on the device:
Display a message that prompts the user to install or update SpenSdk 4.1 apk and open the
website to download the package.
private void processUnsupportedException(SsdkUnsupportedException e) {
e.printStackTrace();
int errorType = e.getType();
// The device is not a Samsung device or it is a Samsung device that does not support S
pen.
if(errorType == SsdkUnsupportedException.VENDOR_NOT_SUPPORTED ||
errorType == SsdkUnsupportedException.DEVICE_NOT_SUPPORTED ) {
Toast.makeText(mContext, "This device does not support Spen.",
Toast.LENGTH_SHORT).show();
finish();
} else if(errorType == SsdkUnsupportedException.LIBRARY_NOT_INSTALLED) {
// SpenSdk 4.1 apk is not installed on the device.
showAlertDialog( "You need to install an additional package"
+ " to use this application."
+ "You will be taken to the installation screen."
+ "Restart this application after the software has been installed."
, true);
} else if(errorType ==
SsdkUnsupportedException.LIBRARY_UPDATE_IS_REQUIRED) {
// The Pen library or SpenSdk 4.1 apk requires to be updated.
showAlertDialog( "You need to update the installed Pen libraryor package"
+ "to use this application."
+ " You will be taken to the installation screen."
dialog.dismiss();
finish();
}
})
.setNegativeButton(android.R.string.no,
new DialogInterface.OnClickListener() {
@Override
public void onClick(
DialogInterface dialog, int which) {
if(closeActivity == true) {
// Terminate the activity if the user does not install it.
finish();
}
dialog.dismiss();
}
}).show();
dlg = null;
}
1. Call Spen.isFeatureEnabled(Spen.DEVICE_PEN) .
.........
isSpenFeatureEnabled = spenPackage.isFeatureEnabled(Spen.DEVICE_PEN);
.........
if(isSpenFeatureEnabled == false) {
mSpenSurfaceView.setToolTypeAction(SpenSurfaceView.TOOL_FINGER,
SpenSurfaceView.ACTION_STROKE);
Toast.makeText(mContext,
"Device does not support S pen. \n You can draw strokeswith your finger",
Toast.LENGTH_SHORT).show();
}
1. Create an SpenNoteDoc instance by passing your application Context and the width and height of
the SpenSurfaceView instance to the SpenNoteDoc constructor. If Pen SDKfails to create a cache
directory, an IOException is thrown.
try {
mSpenNoteDoc =new SpenNoteDoc(mContext, rect.width(), rect.height());
} catch (IOException e) {
e.printStackTrace();
finish();
} catch (Exception e) {
e.printStackTrace();
finish();
}
// After adding a page to NoteDoc, get an instance
// and set it as a member variable.
mSpenPageDoc = mSpenNoteDoc.appendPage();
mSpenPageDoc.setBackgroundColor(0xFFD6E6F5);
mSpenPageDoc.clearHistory();
// Set PageDoc to View.
mSpenSurfaceView.setPageDoc(mSpenPageDoc, true);
To discard the cache data for your SpenNoteDoc instance, call SpenNoteDoc.close() with the Boolean
parameter set to true.
An exception is thrown if you refer to an SpenNoteDoc instance after you have closed it. You can close
SpenNoteDoc and SpenSurfaceView in the onDestroy() method.
if(mSpenSurfaceView != null) {
mSpenSurfaceView.close();
mSpenSurfaceView = null;
}
if(mSpenNoteDoc != null) {
try {
mSpenNoteDoc.close();
} catch (Exception e) {
e.printStackTrace();
}
mSpenNoteDoc = null;
}
mSpenSurfaceView.setToolTypeAction(SpenSurfaceView.TOOL_FINGER,
SpenSurfaceView.ACTION_NONE);
The following tables contain the available tools and actions for SpenSurfaceView.
When the button is clicked, the SpenSettingPenLayout view appears to allow the user to configure the
settings for the Pen SDK. If the button is clicked again, the window closes.
Listener to launch a color picker. When the listener is called, the sample application applies the selected
color to the settings.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pen_setting);
mContext = this;
// Initialize Pen.
boolean isSpenFeatureEnabled = false;
Spen spenPackage = new Spen();
try {
spenPackage.initialize(this);
isSpenFeatureEnabled = spenPackage.isFeatureEnabled(Spen.DEVICE_PEN);
} catch (SsdkUnsupportedException e) {
if( SDKUtils.processUnsupportedException(this, e) == true) {
FrameLayout spenViewContainer =
(FrameLayout) findViewById(R.id.spenViewContainer);
RelativeLayout spenViewLayout =
(RelativeLayout) findViewById(R.id.spenViewLayout);
// Create PenSettingView.
mPenSettingView =
new SpenSettingPenLayout(mContext, new String(),
spenViewLayout);
if (mPenSettingView == null) {
Toast.makeText(mContext, "Cannot create new PenSettingView.",
Toast.LENGTH_SHORT).show();
finish();
}
spenViewContainer.addView(mPenSettingView);
// Create PenView.
mSpenSurfaceView = new SpenSurfaceView(mContext);
if (mSpenSurfaceView == null) {
Toast.makeText(mContext, "Cannot create new SpenSurfaceView.",
Toast.LENGTH_SHORT).show();
finish();
}
spenViewLayout.addView(mSpenSurfaceView);
mPenSettingView.setCanvasView(mSpenSurfaceView);
initPenSettingInfo();
mSpenSurfaceView.setColorPickerListener(mColorPickerListener);
if(isSpenFeatureEnabled == false) {
mSpenSurfaceView.setToolTypeAction(SpenSurfaceView.TOOL_FINGER,
SpenSurfaceView.ACTION_STROKE);
Toast.makeText(mContext,
"Device does not support S pen. \n
You can draw strokeswith your finger",
Toast.LENGTH_SHORT).show();
}
}
@Override
protected void onDestroy() {
if (mPenSettingView != null) {
mPenSettingView.close();
}
if(mSpenSurfaceView != null) {
mSpenSurfaceView.close();
mSpenSurfaceView = null;
}
if(mSpenNoteDoc != null) {
try {
mSpenNoteDoc.close();
} catch (Exception e) {
e.printStackTrace();
}
mSpenNoteDoc = null;
}
};
}
For more information, see PenSample1_2_PenSetting.java in PenSample1_2_PenSetting.
if(errType == SsdkUnsupportedException.VENDOR_NOT_SUPPORTED ||
errType == SsdkUnsupportedException.DEVICE_NOT_SUPPORTED ) {
Toast.makeText(activity, "This device does not support Spen.",
Toast.LENGTH_SHORT).show();
activity.finish();
} else if( errType == SsdkUnsupportedException.LIBRARY_NOT_INSTALLED ) {
// SpenSdk 4.1 apk is not installed on the device.
showAlertDialog( activity,
"You need to install an additional package"
+" to use this application."
+ "You will be taken to the installation screen."
+ "Restart this application after the software has been installed."
, true);
} else if( errType == SsdkUnsupportedException.LIBRARY_UPDATE_IS_REQUIRED ) {
// The Pen library or SpenSdk 4.1 apk requires to be updated.
showAlertDialog( activity,
"You need to update the installed Pen library or package"
+ "to use this application."
+ " You will be taken to the installation screen."
+ " Restart this application after the software has been updated."
, true);
} else if( errType == SsdkUnsupportedException.LIBRARY_UPDATE_IS_RECOMMENDED )
{
// It is recommended that the Pen library or SpenSdk 4.1 apk is updated
// the latest version as possible.
showAlertDialog( activity,
dialog.dismiss();
activity.finish();
}
})
.setNegativeButton(android.R.string.no,
new DialogInterface.OnClickListener() {
@Override
public void onClick(
DialogInterface dialog, int which) {
if(closeActivity == true) {
// Terminate the activity if the user does not install it.
activity.finish();
}
dialog.dismiss();
}
})
.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
if(closeActivity == true) {
// Terminate the activity if the user does not install it.
activity.finish();
}
}
})
.show();
dlg = null;
}
The following sections provide more details on the steps involved in adding settings.
2. To stack the SpenSettingPenLayout view on your SpenSurfaceView instance in the viewport, call
addView() and add your SpenSettingPenLayout instance to the SpenSurfaceView container defined
in FrameLayout.
1. Create an SpenSettingPenInfo instance with your default settings for the pen tool.
Create an OnClickListener listener instance, mPenBtnClickListener in the sample, for the pen Settings
button and register it by calling setOnClickListener() on the button.
In the sample code, setViewMode() is called to switch to the view mode with VIEW_MODE_EXTENSION. In
this mode, you can:
Note
SpenSettingPenLayout provides the following view modes:
View mode Value Settings options for pen tool
VIEW_MODE_NORMAL 0 Type, size, and color
VIEW_MODE_MINIMUM 1 Color, size
VIEW_MODE_EXTENSION 2 Color, type, size, preset, and preview
if (mPenSettingView != null) {
mPenSettingView.close();
}
Note
Instead of using the SpenSettingPenLayout class methods provided in Pen, you can customize
the pen settings for your application. After creating an SpenSettingPenInfo instance, you can
select the options you need and call setPenSettingInfo() to register them. For example, if you
want to add a blue marker for your application, add the following code to the
onClick()method of the button.
If the Clear All button is clicked, all the objects on the viewport are removed and the eraser settings
window is closed.
.........
// Initialize Pen.
boolean isSpenFeatureEnabled = false;
Spen spenPackage = new Spen();
try {
spenPackage.initialize(this);
isSpenFeatureEnabled = spenPackage.isFeatureEnabled(Spen.DEVICE_PEN);
} catch (SsdkUnsupportedException e) {
if( SDKUtils.processUnsupportedException(this, e) == true) {
return;
}
} catch (Exception e1) {
Toast.makeText(mContext, "Cannot initialize Pen.",
Toast.LENGTH_SHORT).show();
e1.printStackTrace();
finish();
}
FrameLayout spenViewContainer =
(FrameLayout) findViewById(R.id.spenViewContainer);
RelativeLayout spenViewLayout =
(RelativeLayout) findViewById(R.id.spenViewLayout);
.........
// Create EraserSettingView.
mEraserSettingView =
new SpenSettingEraserLayout(mContext, new String(),
spenViewLayout);
if (mEraserSettingView == null) {
Toast.makeText(mContext, "Cannot create new EraserSettingView.",
Toast.LENGTH_SHORT).show();
finish();
}
spenViewContainer.addView(mPenSettingView);
spenViewContainer.addView(mEraserSettingView);
// Create PenView.
mSpenSurfaceView = new SpenSurfaceView(mContext);
if (mSpenSurfaceView == null) {
Toast.makeText(mContext, "Cannot create new SpenSurfaceView.",
Toast.LENGTH_SHORT).show();
finish();
}
spenViewLayout.addView(mSpenSurfaceView);
mPenSettingView.setCanvasView(mSpenSurfaceView);
mEraserSettingView.setCanvasView(mSpenSurfaceView);
.........
initSettingInfo();
// Register the listeners.
mSpenSurfaceView.setColorPickerListener(mColorPickerListener);
mEraserSettingView.setEraserListener(mEraserListener);
selectButton(mPenBtn);
if(isSpenFeatureEnabled == false) {
mToolType = SpenSurfaceView.TOOL_FINGER;
mSpenSurfaceView.setToolTypeAction(mToolType,
SpenSurfaceView.ACTION_STROKE);
Toast.makeText(mContext,
"Device does not support S pen. \n
You can draw strokeswith your finger",
Toast.LENGTH_SHORT).show();
}
}
.........
.........
closeSettingView();
}
@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;
}
}
For more information, see PenSample1_3_EraserSetting.java in PenSample1_3_EraserSetting.
The following sections provide more details on the steps involved in adding eraser settings.
To stack the SpenSettingEraserLayout view on your SpenSurfaceView instance in the viewport, call
addView() and add your SpenSettingEraserLayout view to the SpenSurfaceView container defined in
FrameLayout.
.........
mEraserSettingView.setCanvasView(mSpenSurfaceView);
1. Create an SpenSettingEraserInfo instance with a default size for the eraser tool.
.........
Note
If your mToolType in your application is set to any action other than ACTION_ERASER,call
setToolTypeAction()to change it to ACTION_ERASER. This changes the pen mode to eraser mode and the
Eraser Tool button is displayed as selected. Initialize your mToolType variable to
SpenSurfaceView.TOOL_SPEN on devices that support S pen or to SpenSurfaceView.TOOL_FINGER on the
devices that do not support S pen.
if (mEraserSettingView != null) {
mEraserSettingView.close();
}
.........
.........
selectButton(mPenBtn);
}
.........
.........
@Override
public void onUndoable(SpenPageDoc page, boolean undoable) {
// Enable or disable Undo button depending on its availability.
mUndoBtn.setEnabled(undoable);
}
@Override
public void onRedoable(SpenPageDoc page, boolean redoable) {
// Enable or disable Redo button depending on its availability.
mRedoBtn.setEnabled(redoable);
}
.........
The following sections provide more details on the steps involved in adding undo and redo features.
Create an OnClickListener instance for the Undo and Redo buttons, undoNredoBtnClickListener in the
sample, and register it by calling setOnClickListener()on each button.
Refresh the data of the SpenPageDoc instance by calling its Undo() or Redo() methods and refresh the
viewport by calling SpenSurfaceView.updateUndo() or SpenSurfaceView.updateRedo() .
@Override
public void onUndoable(SpenPageDoc page, boolean undoable) {
// Enable or Disable Undo button depending on its availability.
mUndoBtn.setEnabled(undoable);
}
@Override
public void onRedoable(SpenPageDoc page, boolean redoable) {
// Enable or Disable Redo button depending on its availability.
mRedoBtn.setEnabled(redoable);
}
};
Note
Pen SDK limits the number of undoable states to 50. When the fifty first state is added to the
history stack, the oldest state is removed. You can edit the limit by calling
SpenPageDoc.setUndoLimit().
.........
selectButton(mPenBtn);
.........
callGalleryForInputImage(REQUEST_CODE_SELECT_IMAGE_BACKGROUND);
}
};
.........
@Override
protected void Activity(int requestCode, int resultCode,
Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (data == null) {
Toast.makeText(mContext, "Cannot find the image",
Toast.LENGTH_SHORT).show();
return;
}
mSpenPageDoc.setBackgroundImage(imagePath);
mSpenSurfaceView.update();
}
}
}
.........
The following sections provide more details on the steps involved in setting a background.
If you are displaying the Background Settings view when the button is clicked, close the window and call the
private class that fetches the image.
To allow image selection from the gallery, create an intent to call startActivityForResult() in your
private class.
1. Use the onActivityResult()callback methodfor the image selection for the background.
Get the URI of the image file from the intent after checking if the resultCode is RESULT_OK.
if (requestCode == REQUEST_CODE_SELECT_IMAGE_BACKGROUND) {
// Get the image's URI and use the location for background image.
Uri imageFileUri = data.getData();
Cursor cursor =getContentResolver().query(
Uri.parse(imageFileUri.toString()), null, null, null, null);
cursor.moveToNext();
String imagePath =cursor.getString(cursor
.getColumnIndex(MediaStore.MediaColumns.DATA));
mSpenPageDoc.setBackgroundImage(imagePath);
mSpenSurfaceView.update();
}
Note
Pen SDK registers all the background image setting actions in history. You can undo both the
background image from the application startup and the one set by the user. To prevent any
unintentional background image changes, clear the history states by calling clearHistory().
If the Replay button is clicked, SpenSurfaceView.startReplay() replays the drawing from the first object.
When the replay animation is played, the buttons are disabled.
mSpenSurfaceView.setReplayListener(mReplayListener);
.........
selectButton(mPenBtn);
mSpenPageDoc.startRecord();
.........
.........
@Override
public void onProgressChanged(int progress, int id) {
}
@Override
public void onCompleted() {
runOnUiThread(new Runnable() {
@Override
public void run() {
// Enable the buttons when replay animation is complete.
setBtnEnabled(true);
mUndoBtn.setEnabled(mSpenPageDoc.isUndoable());
mRedoBtn.setEnabled(mSpenPageDoc.isRedoable());
}
});
}
};
.........
.........
if (mSpenPageDoc.isRecording()) {
mSpenPageDoc.stopRecord();
}
if (mSpenSurfaceView.getReplayState() ==
SpenSurfaceView.REPLAY_STATE_PLAYING) {
mSpenSurfaceView.stopReplay();
}
.........
The following sections provide more details on the steps involved in replaying drawings.
2. Create an OnClickListener instance for the Replay button, mPlayBtnClickListener in the sample, and
register it by calling setOnClickListener() on the button.
In the onClick() method, close the settings window (if any is displayed) and disable all the buttons on the
viewport.
closeSettingView();
setBtnEnabled(false);
mSpenSurfaceView.startReplay();
In the onCompleted() method, enable all the buttons. Enable the Undo and Redo buttons depending on
their availability.
If the user clicks the Replay button, all the drawn objects from the first object are replayed.
if (mSpenPageDoc.isRecording()) {
mSpenPageDoc.stopRecord();
}
if (mSpenSurfaceView.getReplayState() == SpenSurfaceView.REPLAY_STATE_PLAYING) {
mSpenSurfaceView.stopReplay();
}
Note
You cannot replay the editing of objects with replay animations. Only the final state of each
object is redrawn because a replay animation follows the order of the objects listed in
SpenPageDoc.
.........
selectButton(mPenBtn);
mSpenPageDoc.startRecord();
.........
.........
.........
3. Specify the file name and path for the screen shot.
To register the saved file with the gallery, call sendBroadcast() Intent.ACTION_MEDIA_MOUNTED.
Note
You can also take screen shots of SpenPageDoc instances that are not connected to a
SpenSurfaceView instance. Use the SpenCapturePage class to capture screens that do not have a
View.
Do not use the SpenPageDoc instance connected to your SpenSurfaceView instance with the
SpenCapturePage class methods.
.........
mSpenPageDoc.setBackgroundColor(0);
mSpenPageDoc.clearHistory();
.........
mSpenSurfaceView.setPreDrawListener(mPreDrawListener);
mSpenSurfaceView.setPostDrawListener(mPosteDrawListener);
.........
.........
@Override
public void onDraw(Canvas canvas, float x, float y, float ratio,
float frameStartX, float frameStartY, RectF updateRect) {
Bitmap bm =
((BitmapDrawable) getResources().getDrawable(
R.drawable.canvas_bg)).getBitmap();
canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
canvas.drawBitmap(bm, 0, 0, null);
}
};
@Override
public void onDraw(Canvas canvas, float x, float y, float ratio,
float frameStartX, float frameStartY, RectF updateRect) {
Bitmap bm =
((BitmapDrawable) getResources().getDrawable(
R.drawable.watermark)).getBitmap();
float pointX = (mScreenRect.width() - bm.getWidth()) / 2;
float pointY = mScreenRect.height() / 2 - bm.getHeight();
canvas.drawBitmap(bm, pointX, pointY, null);
}
};
.........
The following sections provide more details on the steps involved in custom drawing.
1. Create a SpenDrawListener instance that is called before Pen SDK displays drawing data on the
SpenSurfaceView instance.
In the onDraw method, add your code for handling the event. The sample code adds the checkered image
by drawing a resource file to the screen.
1. Create a SpenDrawListener instance that is called after Pen SDK displays drawing data on the
SpenSurfaceView instance.
In the onDraw method, add your code for handling the event. The sample code adds the translucent text
image, Samsung Mobile SDK S-Pen Package by drawing a resource file to the screen.
Add Image button to add an image each time the S pen touches the viewport.
Custom mode to generate images on the viewport.
Listener for touch events.
Image object placement and SpenPageDoc instance and viewport update.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image_object);
mContext = this;
// Initialize Pen.
boolean isSpenFeatureEnabled = false;
Spen spenPackage = new Spen();
try {
spenPackage.initialize(this);
isSpenFeatureEnabled =
spenPackage.isFeatureEnabled(Spen.DEVICE_PEN);
} catch (SsdkUnsupportedException e) {
if( SDKUtils.processUnsupportedException(this, e) == true) {
return;
}
} catch (Exception e1) {
Toast.makeText(mContext, "Cannot initialize Pen.",
Toast.LENGTH_SHORT).show();
e1.printStackTrace();
finish();
}
FrameLayout spenViewContainer =
(FrameLayout) findViewById(R.id.spenViewContainer);
RelativeLayout spenViewLayout =
(RelativeLayout) findViewById(R.id.spenViewLayout);
// Create PenSettingView.
mPenSettingView =
new SpenSettingPenLayout(mContext, new String(),
spenViewLayout);
if (mPenSettingView == null) {
Toast.makeText(mContext, "Cannot create new PenSettingView.",
Toast.LENGTH_SHORT).show();
finish();
}
spenViewContainer.addView(mPenSettingView);
// Create PenView.
mSpenSurfaceView = new SpenSurfaceView(mContext);
if (mSpenSurfaceView == null) {
Toast.makeText(mContext, "Cannot create new SpenSurfaceView.",
Toast.LENGTH_SHORT).show();
finish();
initPenSettingInfo();
// Register the listener.
mSpenSurfaceView.setTouchListener(mPenTouchListener);
mSpenSurfaceView.setColorPickerListener(mColorPickerListener);
selectButton(mPenBtn);
if(isSpenFeatureEnabled == false) {
mToolType = SpenSurfaceView.TOOL_FINGER;
mSpenSurfaceView.setToolTypeAction(mToolType,
SpenSurfaceView.ACTION_STROKE);
Toast.makeText(mContext,
"Device does not support S pen. \n You can draw strokeswith
your finger",
Toast.LENGTH_SHORT).show();
}
}
@Override
public boolean onTouch(View view, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP
&& event.getToolType(0) == mToolType) {
// Check if the control is created.
SpenControlBase control = mSpenSurfaceView.getControl();
if (control == null) {
// A touch event occurs in ObjectImage adding mode.
if (mMode == MODE_IMG_OBJ) {
// Set Bitmap file for ObjectImage.
SpenObjectImage imgObj = new SpenObjectImage();
Bitmap imageBitmap =
BitmapFactory.decodeResource(
mContext.getResources(),
R.drawable.ic_launcher);
imgObj.setImage(imageBitmap);
imageBitmap.recycle();
return true;
}
}
}
return false;
}
};
v.setSelected(true);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mPenSettingView != null) {
mPenSettingView.close();
if(mSpenSurfaceView != null) {
mSpenSurfaceView.close();
mSpenSurfaceView = null;
}
if(mSpenNoteDoc != null) {
try {
mSpenNoteDoc.close();
} catch (Exception e) {
e.printStackTrace();
}
mSpenNoteDoc = null;
}
};
}
The following sections provide more details on the steps involved in adding an image object to the screen.
Create an OnClickListener instance for the Add Image button, mImgObjBtnClickListener in the sample,
and register it by calling setOnClickListener()on the button.
In the onClick() method for the Add Image button listener, setmToolTypeto ACTION_NONE, switch to an
internal mode for adding objects, and indicate that the button is selected.
mMode = MODE_IMG_OBJ;
selectButton(mImgObjBtn);
mSpenSurfaceView.setToolTypeAction(SpenSurfaceView.mToolType,
SpenSurfaceView.ACTION_NONE);
Call SpenObjectImage.setImage()to assign your Bitmap object. The sample application users an Android
icon.
Check if the viewport can be zoomed in, zoomed out, or panned, and set the position of the image
accordingly by calling SpenObjectImage.setRect().
imageBitmap.recycle();
return true;
}
}
}
return false;
Note
Before you add an object to an SpenPageDoc instance, set the second input variable to true to
select the area for the object. For example, SpenObjectBase.setRect(rect, true).
In Pen SDK, you can also use setRect()for moving and scaling objects. In that case, set the second
input variable to false. To move an object by (dx, dy), see the following sample code.
RectF rect = object.getRect();
rect.left += dx;
rect.top += dy;
rect.right += dx;
rect.bottom += dy;
object.setRect(rect, false);
Insert Text button to add text boxes each time the pen touches the viewport.
Custom mode for inserting a text box when there is a touch event.
Listener for touch events in the View area.
Text box object insertion and SpenPageDoc instance and viewport update.
If another text box already exists at the coordinates where the touch event takes place, the
SpenSurfaceView instance switches to text editing mode.
If you click the Insert Text button and the action for TOOL_SPEN is ACTION_TEXT, the text property settings
window appears to allow you to change the font size, color, font and type. You can close the window by
clicking the Insert Text button again when the text property window is open.
.........
// Create TextSettingView.
mTextSettingView =
new SpenSettingTextLayout(mContext, new String(),
new HashMap<String, String>(), spenViewLayout);
if (mTextSettingView == null) {
Toast.makeText(mContext, "Cannot create new TextSettingView.",
Toast.LENGTH_SHORT).show();
finish();
}
spenViewContainer.addView(mPenSettingView);
spenViewContainer.addView(mTextSettingView);
.........
initSettingInfo();
// Register the listeners.
mSpenSurfaceView.setTouchListener(mPenTouchListener);
mSpenSurfaceView.setColorPickerListener(mColorPickerListener);
mSpenSurfaceView.setTextChangeListener(mTextChangeListener);
selectButton(mPenBtn);
}
@Override
public boolean onTouch(View view, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP
&& event.getToolType(0) == mToolType) {
// Checks whether the control is generated or not.
SpenControlBase control = mSpenSurfaceView.getControl();
if (control == null) {
// When touching the screen in Insert ObjectImage mode.
if (mMode == MODE_IMG_OBJ) {
// Set the Bitmap file to ObjectImage.
imageBitmap.recycle();
return true;
// When touching the screen in Insert ObjectTextBox mode.
.........
SpenSettingTextInfo textInfo =
mTextSettingView.getInfo();
textInfo.color = color;
mTextSettingView.setInfo(textInfo);
}
}
};
@Override
public boolean onSelectionChanged(int arg0, int arg1) {
return false;
}
@Override
public void onMoreButtonDown(SpenObjectTextBox arg0) {
}
@Override
public void onChanged(SpenSettingTextInfo info, int state) {
if (mTextSettingView != null) {
if (state == CONTROL_STATE_SELECTED) {
mTextSettingView.setInfo(info);
}
}
}
@Override
public void onFocusChanged(boolean arg0) {
}
};
v.setSelected(true);
closeSettingView();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mPenSettingView != null) {
mPenSettingView.close();
}
if (mTextSettingView != null) {
mTextSettingView.close();
}
if(mSpenSurfaceView != null) {
mSpenSurfaceView.closeControl();
mSpenSurfaceView.close();
mSpenSurfaceView = null;
}
if(mSpenNoteDoc != null) {
try {
mSpenNoteDoc.close();
} catch (Exception e) {
e.printStackTrace();
}
mSpenNoteDoc = null;
}
}
The following sections provide more details on the steps involved in adding text events to your application.
Create an OnClickListener instance for the Insert Text button, mTextObjBtnClickListener in the sample,
and register it by calling setOnClickListener()on the button.
In the onClick() method, show the Text Properties view if mToolTypeis set to ACTION_TEXT.
If mToolTypeis not set to ACTION_TEXT, switch to an internal mode for adding text box objects. Indicate
that the button has been selected.
Note
1. Create anSpenTouchListener listener instance and implement the onTouch() callback function to
handle touch events in the viewport.
In the onTouch() method, add a text box object if the tool type is TOOL_SPEN and the action for the tool
type is ACTION_TEXT.
Calculate the location of the text box considering zooming and rotating of the screen and call
SpenObjectTextBox.setRect() to specify the location for inserting the text box.
.........
Note
If the SpenSettingPenLayout window is open when the cursor is placed in the SpenTextBox, call
SpenSettingTextInfo.SetInfo()to add the settings of the text at the cursor to the
SpenSettingPenLayout window.
if (mTextSettingView != null) {
mTextSettingView.close();
}
mSpenSurfaceView.closeControl();
Note
To set the basic properties of your ObjectTextBox instance, call methods such as setFont(),
setFontSize(), setTextStyle(), setTextColor(), and
setBackgroundColor().PenSDK also provides classes for setting paragraphs and spans, and
supports rich text format.
The following classes inherit TextParagraphInfo for setting text paragraph properties:
Class Description
StyleParagraphInfo Style paragraphs with templates.
The following classes inherit TextSpanInfo for setting text paragraph properties:
Class Description
TextDirectionSpanInfo Set the text direction.
FontSizeSpanInfo Set the font size.
FontNameSpanInfo Set text font.
ForegroundColorSpanInfo Set text color.
BackgroundColorSpanInfo Set text background color.
BoldStyleSpanInfo Make text bold.
ItalicStyleSpanInfo Make text italic.
UnderlineStyleSpanInfo Underline text.
Note
text.setTextSpan(spans);
Insert Stroke button to add a stroke each time the pen touches the viewport.
Custom mode to add pen strokes.
Listener for touch events.
Stroke insertion and SpenPageDoc and viewport update.
mSpenSurfaceView.setTouchListener(mPenTouchListener);
.........
selectButton(mPenBtn);
}
.........
@Override
public boolean onTouch(View view, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP
&& event.getToolType(0) == mToolType) {
// Check whether the control is created or not.
SpenControlBase control = mSpenSurfaceView.getControl();
if (control == null) {
.........
SpenObjectStroke strokeObj =
new SpenObjectStroke(
.........
mMode = MODE_STROKE_OBJ;
selectButton(mStrokeObjBtn);
mSpenSurfaceView.setToolTypeAction(mToolType,
SpenSurfaceView.ACTION_NONE);
}
};
.........
v.setSelected(true);
closeSettingView();
}
.........
The following sections provide more details on the steps involved in adding strokes in your application.
In the onClick() method, setmToolTypeto ACTION_NONE, use the internal application stroke mode, and
indicate that the Insert Stroke button is selected.
mMode = MODE_STROKE_OBJ;
selectButton(mStrokeObjBtn);
mSpenSurfaceView.setToolTypeAction(mToolType,
SpenSurfaceView.ACTION_NONE);
In the onTouch () method,if the SpenSurfaceView tool type is S pen and the application internal mode is
Insert Stroke, implement the following:
Calculat e the coordinates of the stroke based on the location where the event took place.
Set the time stamp with the system clock and set Pressure to 1.
Get the pen name from the settings information for use as an input variable to call
SpenObjectStroke().
Call SpenObjectStroke() to create a stroke object. In this case, the size of an array of points and
pressures must always be same; otherwise, an exception will be thrown.
From the setting information, get the pen size and color for the new object and call setPenSize()
and setColor() to set them.
Call SpenPageDoc.appendObject() to insert the stroke object.
Call SpenSurfaceView.update() to refresh the screen.
if (mMode == MODE_STROKE_OBJ) {
//Specify the location where ObjectStroke is inserted
// and add PageDoc.
RectF rect = getRealPoint(event.getX(), event.getY(),0, 0);
float rectX = rect.centerX();
float rectY = rect.centerY();
int pointSize = 157;
float[][] strokePoint = new float[pointSize][2];
for(int i = 0; i < pointSize; i++) {
strokePoint[i][0] = rectX++;
strokePoint[i][1] =(float) (rectY + Math.sin(.04 * i) * 50);
}
PointF[] points = new PointF[pointSize];
float[] pressures = new float[pointSize];
SpenObjectStroke strokeObj =
new SpenObjectStroke(
mPenSettingView.getInfo().name, points,
pressures, timestamps);
strokeObj.setPenSize(mPenSettingView.getInfo().size);
strokeObj.setColor(mPenSettingView.getInfo().color);
mSpenPageDoc.appendObject(strokeObj);
mSpenSurfaceView.update();
}
Note
If the current used pen type is foutain pen, you can use the following API to add tilt/orientation
infomation to the stroke to customize stroke's style:
.........
.........
mSpenSurfaceView.setTouchListener(mPenTouchListener);
mSpenSurfaceView.setControlListener(mControlListener);
selectButton(mPenBtn);
initShapeSelectionDialog();
selectButton(mPenBtn);
}
.........
@Override
public boolean onTouch(View view, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP && event.getToolType(0) ==
mToolType) {
// Check if the control is created.
SpenControlBase control = mSpenSurfaceView.getControl();
if (control == null) {
// When Pen touches the display while it is in Add ObjectShape
mode
} else if (mMode == MODE_SHAPE_OBJ) {
mSpenPageDoc.appendObject(shapeObj);
mSpenSurfaceView.update();
try {
RectF rectLine = getRealPoint(event.getX(), event.getY(),
400, 400);
line = new SpenObjectLine(mShapeObjNumber, new
PointF(rectLine.left, rectLine.top),
new PointF(rectLine.right, rectLine.bottom));
} catch (Exception e) {
mSpenPageDoc.appendObject(line);
mSpenSurfaceView.update();
}
}
}
return false;
}
.........
@Override
public void onRotationChanged(float arg0, SpenObjectBase arg1) {
}
@Override
public void onRectChanged(RectF arg0, SpenObjectBase arg1) {
}
@Override
public void onObjectChanged(ArrayList<SpenObjectBase>arg0) {
}
@Override
public boolean onMenuSelected(ArrayList<SpenObjectBase>objectList, intitemId) {
switch (itemId) {
// Remove the selected object.
caseCONTEXT_MENU_PROPERTIES_ID:
shapeProperties();
mSpenSurfaceView.closeControl();
break;
default:
break;
}
return true;
}
@Override
public boolean onCreated(ArrayList<SpenObjectBase>objectList,
ArrayList<Rect>relativeRectList,
ArrayList<SpenContextMenuItemInfo>menu,
ArrayList<Integer>styleList, intpressType,
PointF point) {
// Set the Context menu
SpenObjectBase object = objectList.get(0);
if (object.getType() == SpenObjectBase.TYPE_SHAPE
|| object.getType() == SpenObjectBase.TYPE_LINE) {
menu.add(new SpenContextMenuItemInfo(CONTEXT_MENU_PROPERTIES_ID,
return true;
}
@Override
public boolean onClosed(ArrayList<SpenObjectBase>arg0) {
return false;
}
};
mSpenSurfaceView.setToolTypeAction(mToolType, SpenSurfaceView.ACTION_NONE);
mSpenSurfaceView.closeControl();
mShapeSelectionDialog.show();
closeSettingView();
}
};
try {
shape = new SpenObjectShape(mShapeObjNumber);
} catch (Exception e) {
Toast.makeText(mContext, "Not supported shape type: " +
mShapeObjNumber, Toast.LENGTH_LONG).show();
return;
}
mSpenPageDoc.appendObject(shape);
mSpenSurfaceView.update();
mShapeSelectionDialog.dismiss();
} else {
mMode = MODE_LINE_OBJ;
SpenObjectLine line = null;
mShapeObjNumber = position - SHAPE_NUM;
try {
line = new SpenObjectLine(mShapeObjNumber, new PointF(100, 100),
new PointF(500, 500));
} catch (Exception e) {
Toast.makeText(mContext, "Not supported line type: " +
mShapeObjNumber, Toast.LENGTH_LONG).show();
return;
}
mSpenPageDoc.appendObject(line);
mSpenSurfaceView.update();
mShapeSelectionDialog.dismiss();
}
}
});
}
if (mObjSelectedType == SpenObjectBase.TYPE_SHAPE) {
((SpenObjectShape) object).getLineStyleEffect(mLineStyleEffect);
((SpenObjectShape) object).getLineColorEffect(mLineColorEffect);
mFillColorEffect = new SpenFillColorEffect();
((SpenObjectShape) object).getFillEffect(mFillColorEffect);
} else if (mObjSelectedType == SpenObjectBase.TYPE_LINE) {
((SpenObjectLine) object).getLineStyleEffect(mLineStyleEffect);
((SpenObjectLine) object).getLineColorEffect(mLineColorEffect);
}
fillColorSpinner.setOnItemSelectedListener(new
AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?>arg0, View arg1, int index,
long arg3) {
fillColorEffect.setSolidColor(colors.get(index));
}
@Override
public void onNothingSelected(AdapterView<?>arg0) {
}
});
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
if (mObjSelectedType == SpenObjectBase.TYPE_LINE) {
// Enable arrow setting view
LinearLayout arrowSettingView = (LinearLayout)
mShapePropertiesDialog.findViewById(R.id.arrowSetting);
arrowSettingView.setVisibility(View.VISIBLE);
arrowBTypeSpinner.setAdapter(adapterArrowBType);
arrowBTypeSpinner.setSelection(mArrowBeginType);
arrowBTypeSpinner.setOnItemSelectedListener(new
AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1, int index, long
arg3) {
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
arrowBSizeSpinner.setAdapter(adapterArrowBSize);
arrowBSizeSpinner.setSelection(mArrowBeginSize);
arrowBSizeSpinner.setOnItemSelectedListener(new
AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1, int index, long
arg3) {
mArrowBeginSize = index;
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
arrowETypeSpinner.setAdapter(adapterArrowEType);
arrowETypeSpinner.setSelection(mArrowEndType);
arrowETypeSpinner.setOnItemSelectedListener(new
AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1, int index, long
arg3) {
mArrowEndType = index;
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
}
@Override
public void onClick(View v) {
if (mObjSelectedType == SpenObjectBase.TYPE_SHAPE) {
// Set Width
if (tbWidthInput.getText().length() == 0) {
tbWidthInput.setError("Please input value");
return;
}
float width = Float.parseFloat(tbWidthInput.getText().toString());
mLineStyleEffect.setWidth(width);
((SpenObjectShape) object).setLineStyleEffect(mLineStyleEffect);
((SpenObjectShape) object).setLineColorEffect(mLineColorEffect);
} else if (mObjSelectedType == SpenObjectBase.TYPE_LINE) {
// Set Width
if (tbWidthInput.getText().length() == 0) {
tbWidthInput.setError("Please input value");
return;
}
float width = Float.parseFloat(tbWidthInput.getText().toString());
mLineStyleEffect.setWidth(width);
mLineStyleEffect.setBeginArrow(mArrowBeginType, mArrowBeginSize);
mLineStyleEffect.setEndArrow(mArrowEndType, mArrowEndSize);
((SpenObjectLine) object).setLineStyleEffect(mLineStyleEffect);
((SpenObjectLine) object).setLineColorEffect(mLineColorEffect);
}
mSpenSurfaceView.update();
mShapePropertiesDialog.dismiss();
}
});
mShapePropertiesDialog.show();
return;
}
v.setSelected(true);
closeSettingView();
}.........
The following sections provide more details on the steps involved in adding shape objects in your
application.
3. In the onCreate()method when the internal action mode is Insert Shape, close the active settings
views (if any) and create a view dialog to userselect type of shape/line from gridview.
4. After users selected, create the shape/line object and append to the pagedoc.
mSpenSurfaceView.setToolTypeAction(mToolType, SpenSurfaceView.ACTION_NONE);
mSpenSurfaceView.closeControl();
mShapeSelectionDialog.show();
closeSettingView();
try {
shape = new SpenObjectShape(mShapeObjNumber);
} catch (Exception e) {
Toast.makeText(mContext, "Not supported shape type: " +
mShapeObjNumber, Toast.LENGTH_LONG).show();
return;
}
mSpenPageDoc.appendObject(shape);
mSpenSurfaceView.update();
mShapeSelectionDialog.dismiss();
} else {
mMode = MODE_LINE_OBJ;
SpenObjectLine line = null;
mShapeObjNumber = position - SHAPE_NUM;
try {
line = new SpenObjectLine(mShapeObjNumber, new PointF(100, 100),
new PointF(500, 500));
} catch (Exception e) {
Toast.makeText(mContext, "Not supported line type: " +
mShapeObjNumber, Toast.LENGTH_LONG)
.show();
return;
}
mSpenPageDoc.appendObject(line);
mSpenSurfaceView.update();
mShapeSelectionDialog.dismiss();
}
}
});
}
In the onTouch()method, if the SpenSurfaceView tool type is Pen and the application internal mode is
Insert Shape or Insert Line, implement the following:
@Override
public boolean onTouch(View view, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP && event.getToolType(0) ==
mToolType) {
// Check if the control is created.
SpenControlBase control = mSpenSurfaceView.getControl();
if (control == null) {
.........
try {
RectF rectLine = getRealPoint(event.getX(), event.getY(), 400, 400);
line = new SpenObjectLine(mShapeObjNumber, new PointF(rectLine.left,
rectLine.top),
new PointF(rectLine.right, rectLine.bottom));
} catch (Exception e) {
Toast.makeText(mContext, "Not supported line type: " + mShapeObjNumber,
Toast.LENGTH_LONG)
.show();
return false;
}
mSpenPageDoc.appendObject(line);
mSpenSurfaceView.update();
}
}
}
return false;
}
};
1. Create an SpenControlListener listener instance to handle state changes in the View area.
In the onCreated() callback method, which is called when a control is displayed in the View area, add a
Properties item to the context menu to change properties a selected shape/line object.
In the onMenuSelected() callback method, which is called when an item is selected from a context menu
appearing on a control, call the following methods:
.........
@Override
return true;
}
@Override
public boolean onCreated(ArrayList<SpenObjectBase> objectList, ArrayList<Rect>
relativeRectList,
ArrayList<SpenContextMenuItemInfo> menu, ArrayList<Integer> styleList, int
pressType, PointF point) {
// Set the Context menu
SpenObjectBase object = objectList.get(0);
if (object.getType() == SpenObjectBase.TYPE_SHAPE || object.getType() ==
SpenObjectBase.TYPE_LINE) { menu.add(new
SpenContextMenuItemInfo(CONTEXT_MENU_PROPERTIES_ID, "Properties", true));
}
return true;
}
@Override
public boolean onClosed(ArrayList<SpenObjectBase> arg0) {
return false;
}
};
private void shapeProperties() {
final SpenObjectBase object = mSpenPageDoc.getSelectedObject().get(0);
mObjSelectedType = object.getType();
if (mObjSelectedType == SpenObjectBase.TYPE_SHAPE) {
((SpenObjectShape) object).getLineStyleEffect(mLineStyleEffect);
((SpenObjectShape) object).getLineColorEffect(mLineColorEffect);
mFillColorEffect = new SpenFillColorEffect();
((SpenObjectShape) object).getFillEffect(mFillColorEffect);
} else if (mObjSelectedType == SpenObjectBase.TYPE_LINE) {
((SpenObjectLine) object).getLineStyleEffect(mLineStyleEffect);
((SpenObjectLine) object).getLineColorEffect(mLineColorEffect);
}
if (mObjSelectedType == SpenObjectBase.TYPE_SHAPE) {
String arrayColor[] = new String[6];
fillColorSpinner.setSelection(colors.indexOf(mFillColorEffect.getSolidColor()));
fillColorSpinner.setOnItemSelectedListener(new
AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1, int index, long
arg3) {
mFillColorEffect.setSolidColor(colors.get(index));
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 100
mShapePropertiesDialog.findViewById(R.id.spDashType);
String arrayDashType[] = new String[8];
arrayDashType[0] = "Solid";
arrayDashType[1] = "Round Dot";
arrayDashType[2] = "Square Dot";
arrayDashType[3] = "Dash";
arrayDashType[4] = "Dash Dot";
arrayDashType[5] = "Long Dash";
arrayDashType[6] = "Long Dash Dot";
arrayDashType[7] = "Long Dash Dot Dot";
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
if (mObjSelectedType == SpenObjectBase.TYPE_LINE) {
// Enable arrow setting view
LinearLayout arrowSettingView = (LinearLayout)
mShapePropertiesDialog.findViewById(R.id.arrowSetting);
arrowSettingView.setVisibility(View.VISIBLE);
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 101
arrowBTypeSpinner.setAdapter(adapterArrowBType);
arrowBTypeSpinner.setSelection(mArrowBeginType);
arrowBTypeSpinner.setOnItemSelectedListener(new
AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1, int index, long
arg3) {
mArrowBeginType = index;
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
arrowBSizeSpinner.setAdapter(adapterArrowBSize);
arrowBSizeSpinner.setSelection(mArrowBeginSize);
arrowBSizeSpinner.setOnItemSelectedListener(new
AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1, int index, long
arg3) {
mArrowBeginSize = index;
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
arrowETypeSpinner.setAdapter(adapterArrowEType);
arrowETypeSpinner.setSelection(mArrowEndType);
arrowETypeSpinner.setOnItemSelectedListener(new
AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1, int index, long
arg3) {
mArrowEndType = index;
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 102
// SPinner Arrow End Size
Spinner arrowESizeSpinner = (Spinner)
mShapePropertiesDialog.findViewById(R.id.spArrowEndSize);
ArrayAdapter<String> adapterArrowESize = new ArrayAdapter<String>(mContext,
android.R.layout.simple_spinner_dropdown_item, arrayArrowSize);
arrowESizeSpinner.setAdapter(adapterArrowESize);
arrowESizeSpinner.setSelection(mArrowEndSize);
arrowESizeSpinner.setOnItemSelectedListener(new
AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1, int index, long
arg3) {
mArrowEndSize = index;
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
}
@Override
public void onClick(View v) {
if (mObjSelectedType == SpenObjectBase.TYPE_SHAPE) {
// Set Width
if (tbWidthInput.getText().length() == 0) {
tbWidthInput.setError("Please input value");
return;
}
float width = Float.parseFloat(tbWidthInput.getText().toString());
mLineStyleEffect.setWidth(width);
((SpenObjectShape) object).setLineStyleEffect(mLineStyleEffect);
((SpenObjectShape) object).setLineColorEffect(mLineColorEffect);
} else if (mObjSelectedType == SpenObjectBase.TYPE_LINE) {
// Set Width
if (tbWidthInput.getText().length() == 0) {
tbWidthInput.setError("Please input value");
return;
}
float width = Float.parseFloat(tbWidthInput.getText().toString());
mLineStyleEffect.setWidth(width);
mLineStyleEffect.setBeginArrow(mArrowBeginType, mArrowBeginSize);
mLineStyleEffect.setEndArrow(mArrowEndType, mArrowEndSize);
((SpenObjectLine) object).setLineStyleEffect(mLineStyleEffect);
((SpenObjectLine) object).setLineColorEffect(mLineColorEffect);
}
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 103
mSpenSurfaceView.update();
mShapePropertiesDialog.dismiss();
}
});
@Override
public void onClick(View v) {
mShapePropertiesDialog.dismiss();
}
});
mShapePropertiesDialog.show();
return;
}
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 104
Note
Pen SDK supports 88 types of Object Shape as following:
ShapeType Value Description
TYPE_UNKNOWN 0 Unknown type
TYPE_OVAL 1 Oval type
TYPE_TRIANGLE 2 Triangle type
TYPE_RIGHT_TRIANGLE 3 Right triangle type
... ... ...
TYPE_QUAD_ARROW_CALLOUT 87 Quaq arrow callout type
You can customize the Object Shape for your application by creating SpenFillColorEffect,
SpenFillImageEffect, SpenFillPatternEffect, SpenLineColorEffect,
SpenLineStyleEffect instance.
Set LineStyleEffect:
Set LineColorEffect:
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 105
Note
You can set start point, end point and type of Object Line when init:
You can customize the Object Line for your application by creating SpenFillColorEffect,
SpenLineColorEffect, SpenLineStyleEffect instance.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 106
3. When Pen Button is pressed, call SpenSurfaceView.setToolTypeAction() and set TOOL_PEN to
ACTION_STROKE
}
};
Typical drawing applications display files saved in an image format as images but applications using Pen SDK
can read them in the SPD data format. When the image data is modified with common editing tools, Pen
SDK applications can no longer open them because these modifications remove the SPD data from the
image data.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 107
Figure 19: File save function
selectButton(mPenBtn);
}
.........
closeSettingView();
saveNoteFile(false);
}
};
private boolean saveNoteFile(final boolean isClose) {
// Prompt Save File dialog to get the file name
// and get its save format option (note file or image).
LayoutInflater inflater = (LayoutInflater)
mContext.getSystemService(LAYOUT_INFLATER_SERVICE);
final View layout = inflater.inflate(R.layout.save_file_dialog, (ViewGroup)
findViewById(R.id.layout_root));
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 108
if (!filePath.mkdirs()) {
Toast.makeText(mContext, "Save Path Creation Error",
Toast.LENGTH_SHORT).show();
return;
}
}
String saveFilePath = filePath.getPath() + '/';
String fileName = inputPath.getText().toString();
if (!fileName.equals("")) {
saveFilePath += fileName;
int checkedRadioButtonId = selectFileExt.getCheckedRadioButtonId();
if (checkedRadioButtonId == R.id.radioNote) {
saveFilePath += ".spd";
saveNoteFile(saveFilePath);
} else if (checkedRadioButtonId == R.id.radioImage) {
saveFilePath += ".png";
captureSpenSurfaceView(saveFilePath);
} else {
}
if (isClose) {
finish();
}
} else {
Toast.makeText(mContext, "Invalid filename !!!",
Toast.LENGTH_LONG).show();
}
}
});
builderSave.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (isClose) {
finish();
}
}
});
return true;
}
private boolean saveNoteFile(String strFileName) {
try {
// Save NoteDoc
mSpenNoteDoc.save(strFileName, false);
Toast.makeText(mContext, "Save success to " + strFileName,
Toast.LENGTH_SHORT).show();
} catch (IOException e) {
Toast.makeText(mContext, "Cannot save NoteDoc file.",
Toast.LENGTH_SHORT).show();
e.printStackTrace();
return false;
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 109
private void captureSpenSurfaceView(String strFileName) {
@Override
public void onBackPressed() {
if (mSpenPageDoc.getObjectCount(true) > 0 && mSpenPageDoc.isChanged()) {
AlertDialog.Builder dlg = new AlertDialog.Builder(mContext);
dlg.setIcon(mContext.getResources().getDrawable(android.R.drawable.ic_dialog_alert));
dlg.setTitle(mContext.getResources().getString(R.string.app_name))
.setMessage("Do you want to exit after save?")
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
saveNoteFile(true);
dialog.dismiss();
}
}).setNeutralButton("No", new DialogInterface.OnClickListener() {
@Override
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 110
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
mIsDiscard = true;
finish();
}
}).setNegativeButton("Cancel", new
DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
}).show();
dlg = null;
} else {
super.onBackPressed();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mPenSettingView != null) {
mPenSettingView.close();
}
if (mTextSettingView != null) {
mTextSettingView.close();
}
if (mSpenSurfaceView != null) {
mSpenSurfaceView.closeControl();
mSpenSurfaceView.close();
mSpenSurfaceView = null;
}
if (mSpenNoteDoc != null) {
try {
if (mIsDiscard) {
mSpenNoteDoc.discard();
} else {
mSpenNoteDoc.close();
}
} catch (Exception e) {
e.printStackTrace();
}
mSpenNoteDoc = null;
}
};
The following sections provide more details on the steps involved in saving a file.
Note
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 111
Note
From Pen SDK 4.0, we support compatibleMode for saving notedoc and saving pagedoc. And the
performance will be bad if compatibleMode of saving notedoc and saving pagedoc are different.
Because the default compatibleMode for both save notedoc data and save pagedoc data is true so if
you want to save the notedoc without compatibleMode, you should use:
SpenPageDoc.setDefaultSaveOption(false);
2. Create anOnClickListener listener instance for the Save File button, mSaveFileBtnClickListener in
the sample, and register it by calling setOnClickListener()onthe button.
In the onClickmethod for the Save File button, close the properties view in the viewport, and call the
saveNoteFile()method to generate a dialog to allow the user to save the files. Pass the Boolean value
false to not close the application after files are saved. In the dialog, the user specifies the name and the
extension (SPD or PNG) for the file.
closeSettingView();
saveNoteFile(false);
To savea file in SPD format, pass the file name to the SpenNoteDoc.save() method. Pen SDK stores the file
in the SPen/ folder in external storage.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 112
Call SpenSurfaceView.captureCurrentView() to get the SpenSurfaceView bitmap.
Encode it in an image format.
Create a FileOuputStream with the file name.
Save the encoded image to this stream.
Pass this stream to the SpenNoteDoc.save() method to add the SPD data behind the image.
Call recycle() to avoid possible memory leaks.
Note
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 113
Note
If you have a image file in sdcard/gallery, you can easily save notedoc to this file by using the notedoc
API
Or:
If the user chooses to save the file, save the file and call saveNoteFile()with the Boolean value set to true
to close the application.
@Override
public void onBackPressed() {
if (mSpenPageDoc.getObjectCount(true) > 0 && mSpenPageDoc.isChanged()) {
AlertDialog.Builder dlg = new AlertDialog.Builder(mContext);
dlg.setIcon(mContext.getResources().getDrawable(android.R.drawable.ic_dialog_alert));
dlg.setTitle(mContext.getResources().getString(R.string.app_name))
.setMessage("Do you want to exit after save?")
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
saveNoteFile(true);
dialog.dismiss();
}
})
If the user chooses not to save the file, call the following methods:
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 114
.setNeutralButton("No", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
mIsDiscard = true;
finish();
}
})
If the user selects Cancel in the dialog, close the dialog and return the application to its previous state.
if (mSpenNoteDoc != null) {
try {
if (mIsDiscard) {
mSpenNoteDoc.discard();
} else {
mSpenNoteDoc.close();
}
} catch (Exception e) {
e.printStackTrace();
}
mSpenNoteDoc = null;
}
};
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 115
Displays a view that shows a list of the SPD and PNG files located in the SPen/ folder in external
storage.
Creates an SpenNoteDoc instance with the selected file to refresh the screen with the loaded
SpenPageDoc.
closeSettingView();
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 116
loadNoteFile();
}
};
.........
try
{ SpenObjectTextBox.setInitialCursorPos(SpenObjectTextBox.CURSOR_POS_END);
// Create NoteDoc with the selected file.
SpenNoteDoc tmpSpenNoteDoc = new SpenNoteDoc(mContext,
strFilePath, mScreenRect.width(),
SpenNoteDoc.MODE_WRITABLE, true);
mSpenNoteDoc.close();
mSpenNoteDoc = tmpSpenNoteDoc;
if (mSpenNoteDoc.getPageCount() == 0) {
mSpenPageDoc = mSpenNoteDoc.appendPage();
} else {
mSpenPageDoc =
mSpenNoteDoc.getPage(mSpenNoteDoc.getLastEditedPageIndex());
}
mSpenSurfaceView.setPageDoc(mSpenPageDoc, true);
mSpenSurfaceView.update();
Toast.makeText(mContext, "Successfully loaded noteFile.",
Toast.LENGTH_SHORT).show();
} catch (IOException e) {
Toast.makeText(mContext, "Cannot open this file.",
Toast.LENGTH_LONG).show();
} catch (SpenUnsupportedTypeException e) {
Toast.makeText(mContext, "This file is not supported.",
Toast.LENGTH_LONG).show();
} catch (SpenInvalidPasswordException e) {
Toast.makeText(mContext, "This file is locked by a password.",
Toast.LENGTH_LONG).show();
} catch (SpenUnsupportedVersionException e) {
Toast.makeText(mContext, "This file is the version that does
not support.",
Toast.LENGTH_LONG).show();
} catch (Exception e) {
Toast.makeText(mContext, "Failed to load noteDoc.",
Toast.LENGTH_LONG).show();
}
}
}).show();
}
private String[] setFileList() {
// Call the file list under the directory in mFilePath.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 117
if (!mFilePath.exists()) {
if (!mFilePath.mkdirs()) {
Toast.makeText(mContext, "Save Path Creation Error",
Toast.LENGTH_SHORT).show();
return null;
}
}
// Filter in spd and png files.
File[] fileList = mFilePath.listFiles(new txtFileFilter());
if (fileList == null) {
Toast.makeText(mContext, "File does not exist.", Toast.LENGTH_SHORT).show();
return null;
}
int i = 0;
String[] strFileList = new String[fileList.length];
for (File file : fileList) {
strFileList[i++] = file.getName();
}
return strFileList;
}
.........
The following sections provide more details on the steps involved in loading SPD and +SPD (image file with
added SPD data) files.
In the onClick() method, close all the open settingsview and call the file selection view.
closeSettingView();
loadNoteFile();
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 118
In the file selection view, create a window to display a list of theSPD and PNG files in the SPen/ folder in
external storage to allow users to select a file.
try {
// Create NoteDoc with the selected file.
SpenNoteDoc tmpSpenNoteDoc = new SpenNoteDoc(mContext,
strFilePath, mScreenRect.width(), SpenNoteDoc.MODE_WRITABLE, true);
mSpenNoteDoc.close();
mSpenNoteDoc = tmpSpenNoteDoc;
if (mSpenNoteDoc.getPageCount() == 0) {
mSpenPageDoc = mSpenNoteDoc.appendPage();
} else {
mSpenPageDoc = mSpenNoteDoc.getPage(
mSpenNoteDoc.getLastEditedPageIndex());
}
mSpenSurfaceView.setPageDoc(mSpenPageDoc, true);
mSpenSurfaceView.update();
} catch (IOException e) {
Toast.makeText(mContext,"Cannot open this file.",
Toast.LENGTH_LONG).show();
} catch (SpenUnsupportedTypeException e) {
Toast.makeText(mContext,"This file is not supported.",
Toast.LENGTH_LONG).show();
} catch (SpenInvalidPasswordException e) {
Toast.makeText(mContext,"This file is locked by a password.",
Toast.LENGTH_LONG).show();
} catch (SpenUnsupportedVersionException e) {
Toast.makeText(mContext, "This file is a version that is not supported.",
Toast.LENGTH_LONG).show();
} catch (Exception e) {
Toast.makeText(mContext, "Failed to load noteDoc.",
Toast.LENGTH_LONG).show();
}
When a new SpenNoteDoc instance is successfully created with the selected file, call close()to close the
old SpenNoteDoc. Specify the new SpenNoteDoc instance as a member variable of mSpenNoteDoc.
If the new SpenNoteDoc instance does not have a page, call SpenNoteDoc.appendPage() to create a new
SpenPageDoc instance; otherwise, use the value returned by getLastEditedPageIndex() to call
SpenNoteDoc.getPage()for getting the last edited page.
Call SpenSurfaceView.setPageDoc() to link the page information and your SpenSurfaceView instance.
Call SpenSurfaceView.update()to refresh the screen with the loaded file data.
SpenUnsupportedTypeException is thrown if Pen SDK cannot read the format of the selected file.
SpenInvalidPasswordException is thrown if an invalid password is entered for an encrypted file.
SpenUnsupportedVersionException is thrown if PenSDK does not support the SPD file format
version.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 119
4.2.7. Attaching External Files
You can use Pen SDK to attach external files to SpenNoteDoc to make them available in your applications.
Insert Image button for adding images. Section 4.3.1. Adding Image Objects also uses the image
that the application attaches in this sample.When the Insert Image button is clicked, a dialog
appears to ask whether you want to attach a file. When you select Yes, it displays the information
that a large attachment may take a long time to insert.
Displays a list of selectable image files.
Whenthe Insert Image button is selected, the application creates an image object with the attached
data when you touchanywhere in the View area with your pen, inserts it in SpenPageDoc and
refreshes the screen.
@Override
public boolean onTouch(View view, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP && event.getToolType(0) ==
mToolType) {
// Check if the control is created.
SpenControlBase control = mSpenSurfaceView.getControl();
if (control == null) {
// When Pen touches the display while it is in Add ObjectImage mode
if (mMode == MODE_IMG_OBJ) {
SpenObjectImage imgObj = new SpenObjectImage();
Bitmap imageBitmap;
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 120
// Set a bitmap file to ObjectImage.
// If there is a file attached, set it to ObjectImage.
if (mSpenNoteDoc.hasAttachedFile(ATTACH_IMAGE_KEY)) {
imageBitmap =
BitmapFactory.decodeFile(mSpenNoteDoc.getAttachedFile(ATTACH_IMAGE_KEY));
// If there is no file attached, set the launcher icon to
ObjectImage.
} else {
imageBitmap = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.ic_launcher);
}
imgObj.setImage(imageBitmap);
imageBitmap.recycle();
return true;
.........
};
private RectF
getRealPoint(float x, float y, float width, float height) {
float panX = mSpenSurfaceView.getPan().x;
float panY = mSpenSurfaceView.getPan().y;
float zoom = mSpenSurfaceView.getZoomRatio();
width *= zoom;
height *= zoom;
RectF realRect = new RectF();
realRect.set(
(x - width / 2) / zoom + panX, (y - height / 2) / zoom + panY,
(x + width / 2) / zoom + panX, (y + height / 2) / zoom + panY);
return realRect;
}
.........
if (mMode == MODE_IMG_OBJ) {
closeSettingView();
AlertDialog.Builder dlg = new AlertDialog.Builder(mContext);
dlg.setIcon(mContext.getResources().getDrawable(android.R.drawable.ic_dialog_alert));
dlg.setTitle(mContext.getResources().getString(R.string.app_name))
.setMessage("Change the object image. Continue?")
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 121
changeImgObj();
// finish dialog
dialog.dismiss();
}
}).setNegativeButton("No", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
}).show();
dlg = null;
} else {
mMode = MODE_IMG_OBJ;
selectButton(mImgObjBtn);
mSpenSurfaceView.setToolTypeAction(mToolType, SpenSurfaceView.ACTION_NONE);
}
}
};
.........
dlg.setIcon(mContext.getResources().getDrawable(android.R.drawable.ic_dialog_alert));
dlg.setTitle(mContext.getResources().getString(R.string.app_name))
.setMessage(
"When you select an image, copy the image in NoteDoc data. \n" +
"If the image is large,"
+ " the function is slow and it takes a long time to
save/load.")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
callGalleryForInputImage(REQUEST_CODE_ATTACH_IMAGE);
// Close the dialog.
dialog.dismiss();
}
}).show();
dlg = null;
}
private void callGalleryForInputImage(int nRequestCode) {
// Get the image from the gallery.
try {
Intent galleryIntent = new Intent(Intent.ACTION_GET_CONTENT);
galleryIntent.setType("image/*");
startActivityForResult(galleryIntent, nRequestCode);
} catch (ActivityNotFoundException e) {
Toast.makeText(mContext, "Cannot find gallery activity.",
Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 122
if (resultCode == RESULT_OK) {
if (data == null) {
Toast.makeText(mContext, "Cannot find the image",
Toast.LENGTH_SHORT).show();
return;
}
The following sections provide more details on the steps involved in attaching a file.
3. In the onCreate() method when the internal action mode is insert image, close the active settings
views (if any) and create a dialog box to ask users if they want to change the image.
4. When users select yes, create a dialog to warn them that large images may take some time to load.
If they continue, create an intent to call startActivityForResult() to select an image file from
the device gallery application.
closeSettingView();
AlertDialog.Builder dlg = new AlertDialog.Builder(mContext);
dlg.setIcon(mContext.getResources().getDrawable(android.R.drawable.ic_dialog_alert));
dlg.setTitle(mContext.getResources().getString(R.string.app_name))
.setMessage("Change the object image. Continue?")
.setPositiveButton("Yes", new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which) {
changeImgObj();
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 123
// finish dialog
dialog.dismiss();
}
}).setNegativeButton("No", new
DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
}).show();
dlg = null;
2. Get the URI of the image file from the transferred intent and call SpenNoteDoc.attachFile() to
attach the file. Use "Attach Image Key" as the key value to get the attached file.
If another attached file already exists, detach the old file and attach the new file.
Copy it to SpenNoteDoc.
if (requestCode == REQUEST_CODE_ATTACH_IMAGE) {
// Get the image uri and extract the file path to attach the file.
Uri imageFileUri = data.getData();
Cursor cursor =
getContentResolver().query(
Uri.parse(imageFileUri.toString()), null, null,null, null);
cursor.moveToNext();
String imagePath =
cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DATA));
mSpenNoteDoc.attachFile(ATTACH_IMAGE_KEY, imagePath);
}
3. If the tool type of SpenSurfaceView is S pen and the internal application action mode is Insert
Image, in onTouch () call SpenNoteDoc.hasAttachFile() to check whether a file exists that
corresponds to the key value of "Attach Image Key".
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 124
4. If a file is attached, call SpenNoteDoc.getAttachFile()to change the acquired file into a bitmap.
5. Call SpenObjectImage.setImage() to set the bitmap as an image for Insert Image. Otherwise,
change the default icon image natively supplied by Android into a bitmap, and call
SpenObjectImage.setImage()to specify the bitmap as an image for theInsert Image feature.
if (mSpenNoteDoc.hasAttachedFile(ATTACH_IMAGE_KEY)) {
imageBitmap =BitmapFactory.decodeFile(mSpenNoteDoc
.getAttachedFile(ATTACH_IMAGE_KEY));
// If no attached file is found, the launcher icon is used as
// ObjectImage.
} else {
imageBitmap =BitmapFactory.decodeResource(
mContext.getResources(),
R.drawable.ic_launcher);
}
imgObj.setImage(imageBitmap);
Note
Pen SDK uses the file selected as an input variable for the
SpenNoteDoc.attachFile()method and copies it to the active SpenNoteDoc. Pen SDK takes
a long time to save large files in the SPD format using attachFile(), or to load them.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 125
Figure 22: Page Add function
mSpenSurfaceView.setFlickListener(mFlickListener);
.........
.........
.........
@Override
public void onFinish() {
mAddPageBtn.setClickable(true);
}
});
mSpenSurfaceView.closeControl();
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 126
closeSettingView();
// Create a page next to the current page.
mSpenPageDoc =
mSpenNoteDoc.insertPage(mSpenNoteDoc.getPageIndexById(mSpenPageDoc.getId()) + 1);
mSpenPageDoc.setBackgroundColor(0xFFD6E6F5);
mSpenPageDoc.clearHistory();
v.setClickable(false);
mSpenSurfaceView.setPageDoc(mSpenPageDoc,
SpenSurfaceView.PAGE_TRANSITION_EFFECT_RIGHT,
SpenSurfaceView.PAGE_TRANSITION_EFFECT_TYPE_SHADOW, 0);
.........
@Override
public boolean onFlick(int direction) {
int pageIndex = mSpenNoteDoc.getPageIndexById(mSpenPageDoc.getId());
int pageCount = mSpenNoteDoc.getPageCount();
boolean checkSetPageDoc = false;
if (pageCount > 1) {
// Flick left and turn to the previous page.
if (direction == DIRECTION_LEFT) {
mSpenPageDoc = mSpenNoteDoc.getPage((pageIndex + pageCount - 1) %
pageCount);
if (mSpenSurfaceView.setPageDoc(mSpenPageDoc,
SpenSurfaceView.PAGE_TRANSITION_EFFECT_LEFT,
SpenSurfaceView.PAGE_TRANSITION_EFFECT_TYPE_SHADOW, 0) == true)
{
checkSetPageDoc = true;
} else {
checkSetPageDoc = false;
mSpenPageDoc = mSpenNoteDoc.getPage(pageIndex);
}
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 127
}
return false;
}
};
.........
The following sections provide more details on the steps involved in adding a page.
2. Create an OnClickListener listener instance for the Add Page button, mAddPageBtnClickListener
in the sample,and register it by calling setOnClickListener() on the button.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 128
mSpenSurfaceView.setPageEffectListener(
new SpenPageEffectListener() {
@Override
public void onFinish() {
mAddPageBtn.setClickable(true);
}
});
mTxtView = (TextView) findViewById(R.id.spen_page);
mTxtView.setText("Page"+ mSpenNoteDoc.getPageIndexById(mSpenPageDoc.getId()));
When the number of pages in the note is greater than 1 and a flick event occurs, call
SpenNoteDoc.getPage() to get either the previous or next page depending on the flick direction.
Call SpenSurfaceView.setPageDoc() to set the page as the current page of the SpenSurfaceView instance.
Display a text that shows the index of the current page in the View area.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 129
}
if (checkSetPageDoc == true) {
mTxtView.setText("Page" +
mSpenNoteDoc.getPageIndexById(mSpenPageDoc.getId()));
}
return true;
}
return false;
}
.........
if (note.hasExtraDataString("STRING_KEY")) {
String str = note.getExtraDataString("STRING_KEY");
}
You can use the methods listed in the following table in the SpenNoteDoc, SpenPageDoc, and
SpenObjectBase classes to save extra data in a note, page, or object. PenSDK does not record changes
made to set up extra data in the historystack. You cannot restore extra data with the Undo command.
Method Description
setExtraDataString Sets extra data for the specified key.
setExtraDataInt
setExtraDataStringArray
setExtraDataByteArray
getExtraDataString Returns extra data that corresponds to the specified key.
getExtraDataInt
getExtraDataStringArray
getExtraDataByteArray
hasExtraDataString Checks whether there is extra data that corresponds to the
hasExtraDataInt specified key.
hasExtraDataStringArray
hasExtraDataByteArray
removeExtraDataString Removes extra data thatcorresponds to the specified key.
removeExtraDataInt
removeExtraDataStringArray
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 130
Method Description
removeExtraDataByteArray
Note
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 131
Note
PenSDK does not allow the selected object to be relocated or rotated. The setMovable() or
setRotatable() methods handlethe relocation or rotation modes respectively. Use
setResizeOption()to resize objects.
Pen supports the following resize options:
Resize option Value Description
RESIZE_OPTION_FREE 0 Ignores the aspect ratio when resizing objects.
RESIZE_OPTION_KEEP_RATIO 1 Keeps the aspect ratio when resizing objects.
RESIZE_OPTION_DISABLE 2 Disables object resizing.
PenSDK applies these option values when editing in SpenSurfaceView. For example, if
SpenObjectBase.isRotatable()returns false, you can use setRotation() to allow
rotation of the object.
.........
.........
@Override
public boolean onTouch(View view, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP && event.getToolType(0) ==
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 132
mToolType) {
// Check if the control is created.
SpenControlBase control = mSpenSurfaceView.getControl();
if (control == null) {
// When Pen touches the display while it is in Add ObjectImage mode
if (mMode == MODE_IMG_OBJ) {
addImgObject(event.getX(), event.getY());
return true;
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 133
SpenSurfaceView.ACTION_SELECTION);
}
}
};
.........
imageBitmap.recycle();
}
private SpenObjectTextBox addTextObject(float x, float y, String str) {
// Set the location to insert ObjectTextBox and add it to PageDoc.
SpenObjectTextBox textObj = new SpenObjectTextBox();
RectF rect = getRealPoint(x, y, 0, 0);
rect.right += 350;
rect.bottom += 120;
textObj.setRect(rect, true);
textObj.setText(str);
mSpenPageDoc.appendObject(textObj);
mSpenSurfaceView.update();
return textObj;
}
private SpenObjectShape addShapeObject(float x, float y, int type, String str) {
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 134
SpenObjectShape shapeObj = null;
try {
shapeObj = new SpenObjectShape(type);
} catch (Exception e) {
Toast.makeText(mContext, "Not supported shape type: " + type,
Toast.LENGTH_LONG).show();
return null;
}
RectF rect = getRealPoint(x, y, 300, 300);
shapeObj.setRect(rect, false);
shapeObj.setText(str);
mSpenPageDoc.appendObject(shapeObj);
mSpenSurfaceView.update();
return shapeObj;
}
mSpenPageDoc.appendObject(lineObj);
mSpenSurfaceView.update();
return lineObj;
}
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 135
}
PointF[] points = new PointF[pointSize];
float[] pressures = new float[pointSize];
int[] timestamps = new int[pointSize];
@Override
public void onRotationChanged(float arg0, SpenObjectBase arg1) {
}
@Override
public void onRectChanged(RectF arg0, SpenObjectBase arg1) {
}
@Override
public void onObjectChanged(ArrayList<SpenObjectBase> arg0) {
}
@Override
public boolean onMenuSelected(ArrayList<SpenObjectBase> objectList, int itemId) {
switch (itemId) {
// Remove the selected object.
case CONTEXT_MENU_DELETE_ID:
// mSpenPageDoc.removeSelectedObject();
for (SpenObjectBase obj : objectList) {
mSpenPageDoc.removeObject(obj);
}
mSpenSurfaceView.closeControl();
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 136
mSpenSurfaceView.update();
break;
@Override
public boolean onCreated(ArrayList<SpenObjectBase> objectList, ArrayList<Rect>
relativeRectList,
ArrayList<SpenContextMenuItemInfo> menu, ArrayList<Integer> styleList, int
pressType, PointF point) {
// Set context menu.
if (objectList.size() == 1
&& (objectList.get(0).getType() == SpenObjectBase.TYPE_SHAPE ||
objectList.get(0).getType() == SpenObjectBase.TYPE_LINE)) {
menu.add(new SpenContextMenuItemInfo(CONTEXT_MENU_PROPERTIES_ID,
"Properties", true));
}
menu.add(new SpenContextMenuItemInfo(CONTEXT_MENU_DELETE_ID, "Delete", true));
return true;
}
@Override
public boolean onClosed(ArrayList<SpenObjectBase> arg0) {
return false;
}
};
v.setSelected(true);
closeSettingView();
}
.........
The following sections provide more details on the steps involved in selecting an object.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 137
1. Create a Selection Tool button.
Note
If the action for the tool type is set to ACTION_SELECTION, you do not have to implement
SpenTouchListener to select objects because the touched object is auto-selected. You can get
the objects by calling findObjectAtPosition(), findObjectInClosedCurve(),
findObjectInRect() and findTopObjectAtPosition(). PenSDK provides the following
view modes:
Type filter Value Description
FIND_TYPE_STROKE 1 To get stroke objects.
FIND_TYPE_TEXT_BOX 2 To get text box objects.
FIND_TYPE_IMAGE 4 To get image objects.
FIND_TYPE_CONTAINER 8 To get object containers.
FIND_TYPE_ALL 31 To get all types of objects.
1. Create anSpenControlListener listener instance tohandle state changes in the View area.
In the onCreated() callback method, which is called when a control is displayed in the View area, add a
Delete item to the context menu to delete a selected object.
In the onMenuSelected() callback method, which is called when an item is selected from a context menu
appearing on a control, call the following methods:
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 138
SpenPageDoc.removeSelectedObject() to delete the selected object.
Note
PenSDK offers easy-to-format context menus depending on the selected object. As shown in the
following sample code, SpenControlListener.onCreated()creates an
SpenContextMenuItemInfo instance to add your menu items to the context menu. When you
select an item from the context menu, onMenuSelected() is called to execute the selected
item(command).
@Override
public void onRotationChanged(float arg0, SpenObjectBase arg1) {
}
@Override
public void onRectChanged(RectF arg0, SpenObjectBase arg1) {
}
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 139
Note
@Override
public void onObjectChanged(ArrayList<SpenObjectBase> arg0) {
}
@Override
public boolean onMenuSelected(ArrayList<SpenObjectBase> objectList,
int itemId) {
switch (itemId) {
// Remove the selected object.
case CONTEXT_MENU_DELETE_ID:
// mSpenPageDoc.removeSelectedObject();
for (SpenObjectBase obj : objectList) {
mSpenPageDoc.removeObject(obj);
}
mSpenSurfaceView.closeControl();
mSpenSurfaceView.update();
break;
@Override
public boolean onCreated(ArrayList<SpenObjectBase> objectList,
ArrayList<Rect> relativeRectList,
ArrayList<SpenContextMenuItemInfo> menu, ArrayList<Integer>
styleList, int pressType, PointF point) {
// Set context menu.
if (objectList.size() == 1
&& (objectList.get(0).getType() ==
SpenObjectBase.TYPE_SHAPE || objectList.get(0).getType() ==
SpenObjectBase.TYPE_LINE)) {
menu.add(new
SpenContextMenuItemInfo(CONTEXT_MENU_PROPERTIES_ID, "Properties",
true));
}
menu.add(new SpenContextMenuItemInfo(CONTEXT_MENU_DELETE_ID,
"Delete", true));
return true;
}
@Override
public boolean onClosed(ArrayList<SpenObjectBase> arg0) {
return false;
}
};
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 140
4.3.2. Using the Rectangle and Lasso Selection Tool
You can use Pen SDK to create a tool for selecting an object on the SpenSurfaceView instance.
Pen SDK offers SpenSettingSelectionLayout, which enables you to set up the following two types of object
selections:
Lasso selection, which allows you to draw a selection border to select the object enclosed in the
shape you draw.
Rectangle selection,which allows you to draw a rectangle to select the object enclosed by the
rectangle.
The sample application implements the following features:
Adds SpenSettingSelectionLayout to the sample application created in the Selecting Top Objects
section.
When the Selection Tool button is clicked, the onClick() callback method displays the
SpenSettingSelectionLayout viewtolet users specify the selection type: Lasso or Rectangle.
One or multiple object selection.
// Create SelectionSettingView
mSelectionSettingView = new SpenSettingSelectionLayout(mContext, "", spenViewLayout);
if (mSelectionSettingView == null) {
Toast.makeText(mContext, "Cannot create new SelectionSettingView.",
Toast.LENGTH_SHORT).show();
finish();
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 141
}
mSettingView = (FrameLayout) findViewById(R.id.settingView);
mSettingView.addView(mPenSettingView);
mSettingView.addView(mSelectionSettingView);
// Create SpenSurfaceView
mSpenSurfaceView = new SpenSurfaceView(mContext);
if (mSpenSurfaceView == null) {
Toast.makeText(mContext, "Cannot create new SpenSurfaceView.",
Toast.LENGTH_SHORT).show();
finish();
}
mSpenSurfaceView.setToolTipEnabled(true);
spenViewLayout.addView(mSpenSurfaceView);
mPenSettingView.setCanvasView(mSpenSurfaceView);
mTextSettingView.setCanvasView(mSpenSurfaceView);
mSelectionSettingView.setCanvasView(mSpenSurfaceView);
.........
mSpenSurfaceView.setSelectionChangeListener(mSelectionListener);
.........
.........
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 142
@Override
public void onChanged(SpenSettingSelectionInfo info) {
// Close Setting view if selection type is changed.
mSelectionSettingView.setVisibility(SpenSurfaceView.GONE);
}
};
v.setSelected(true);
closeSettingView();
}
private void closeSettingView() {
// Close all the setting views.
mPenSettingView.setVisibility(SpenSurfaceView.GONE);
mTextSettingView.setVisibility(SpenSurfaceView.GONE);
mSelectionSettingView.setVisibility(SpenSurfaceView.GONE);
}
protected void onDestroy() {
super.onDestroy();
if (mPenSettingView != null) {
mPenSettingView.close();
}
if (mTextSettingView != null) {
mTextSettingView.close();
}
if (mSelectionSettingView != null) {
mSelectionSettingView.close();
}
if (mSpenSurfaceView != null) {
mSpenSurfaceView.closeControl();
mSpenSurfaceView.close();
mSpenSurfaceView = null;
}
if (mSpenNoteDoc != null) {
try {
if (mIsDiscard) {
mSpenNoteDoc.discard();
} else {
mSpenNoteDoc.close();
}
} catch (Exception e) {
e.printStackTrace();
}
mSpenNoteDoc = null;
}
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 143
};
The following sections provide more details on the steps involved in using the Rectangle and Lasso selection
tools.
.........
mSelectionSettingView.setCanvasView(mSpenSurfaceView);
2. Create an OnClickListener listener instance for the Selection Tool button and register it by calling
setOnClickListener()onthe button.
In the onClick() method, if mToolType is set to ACTION_SELECTION and the Selection Tool button is
clicked again., add the following:
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 144
if (mSpenSurfaceView.getToolTypeAction(mToolType) == SpenSurfaceView.ACTION_SELECTION)
{
// If SelectionSettingView is open, close it.
if (mSelectionSettingView.isShown()) {
mSelectionSettingView.setVisibility(View.GONE);
// If SelectionSettingView is not open, open it.
} else {
mSelectionSettingView.setVisibility(View.VISIBLE);
}
2. Add the onChanged() callback method, which is called when selection settings change
if (mSelectionSettingView != null) {
mSelectionSettingView.close();
}
Context menu for grouping multiple objects. The menuappears when multiple objects are located
within the selected area.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 145
Registers the group of objects internally in SpenObjectContainer.
Context menu for ungrouping grouped objects. This menu appears when the area where the
selected objects are grouped is touched
When users select Ungroup from the context menu, SpenPageDoc.ungroupObject() is called to
ungroup the objects.
mSpenSurfaceView.setControlListener(mControlListener);
mSpenSurfaceView.setSelectionChangeListener(mSelectionListener);
// Set the button.
mSelectionBtn = (ImageView) findViewById(R.id.selectionBtn);
mSelectionBtn.setOnClickListener(mSelectionBtnClickListener);
.........
.........
@Override
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 146
public void onRotationChanged(float arg0, SpenObjectBase arg1) {
}
@Override
public void onRectChanged(RectF arg0, SpenObjectBase arg1) {
}
@Override
public void onObjectChanged(ArrayList<SpenObjectBase> arg0) {
}
@Override
public boolean onMenuSelected(ArrayList<SpenObjectBase> objectList, int itemId) {
SpenObjectContainer objContainer;
switch (itemId) {
// Properties of object shape/line
case CONTEXT_MENU_PROPERTIES_ID:
shapeProperties();
mSpenSurfaceView.closeControl();
break;
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 147
return true;
}
@Override
public boolean onCreated(ArrayList<SpenObjectBase> objectList, ArrayList<Rect>
relativeRectList,
ArrayList<SpenContextMenuItemInfo> menu, ArrayList<Integer> styleList, int
pressType, PointF point) {
return false;
}
@Override
public boolean onClosed(ArrayList<SpenObjectBase> arg0) {
return false;
}
};
.........
The following sections provide more details on the steps involved in usingthe group and ungroup object
features.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 148
4.3.3.1 Creating a Context Menu in aControl
To create a context menu when control events occur in your application:
In the onCreated() callback method,which is called when there is a control in the View area, create a
context menu as follows:
Add the Delete menu item to the context menu so that users can select and delete an object.
Add the Group menu item to the context menu when users select more than one object.
Add the Ungroup menu item to the context menu when users select objects with at least one
SpenObjectContainer, which indicates that grouped objects are present.
Create SpenContextMenuItemInfo to register these commands in the context menu.
Create an SpenControlList instance and call setObject() to link controls for each object when
multiple objects are selected.
Call SpenControlList.setGroup() and pass the Boolean value false.
Call SpenSurfaceView.setControl() .
Return the Boolean value false to link controls for selected objects to one another.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 149
}
// Attach an individual control for each object.
SpenControlList controlList = new SpenControlList(mContext, mSpenPageDoc);
controlList.setObject(objectList);
controlList.setGroup(false);
mSpenSurfaceView.setControl(controlList);
controlList.setContextMenu(menu);
return false;
}
1. In the onMenuSelected() callback method, which is called when a menu item is selected from the
context menu on a control, execute the menu items using their menu IDs.
Call SpenPageDoc.groupObject() and pass the list of selected objectsto get an instance of
SpenObjectContainer for the grouped objects.
Pass this instance when calling SpenPageDoc.selectObject().
Call SpenSurfaceView.update()to refresh the screen.
When the Ungroup menu itemis selected, do the following:
Browse the object list to check for an object of the type SpenObjectContainer and call
SpenPageDoc.unGroup() to ungroup the object.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 150
// Remove the selected object.
case CONTEXT_MENU_DELETE_ID:
// mSpenPageDoc.removeSelectedObject();
for (SpenObjectBase obj : objectList) {
mSpenPageDoc.removeObject(obj);
}
mSpenSurfaceView.closeControl();
mSpenSurfaceView.update();
break;
return true;
}
This functionality is added to the sample application that implementedGrouping and Ungrouping Objects.
Adds the following menu items to the control created for Grouping and Ungrouping Objects:
o Move to bottom to send the selected object to the bottom of a group of stacked objects.
o "Move backward" to send the selected object back one level.
o "Move forward" to bring the selected object forward one level.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 151
o "Move to top" to bring the selected object to the top of a group of stacked objects.
mSpenSurfaceView.setControlListener(mControlListener);
mSpenSurfaceView.setSelectionChangeListener(mSelectionListener);
// Set the button.
mSelectionBtn = (ImageView) findViewById(R.id.selectionBtn);
mSelectionBtn.setOnClickListener(mSelectionBtnClickListener);
.........
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 152
SpenObjectLine.TYPE_STRAIGHT);
.........
.........
@Override
public void onRotationChanged(float arg0, SpenObjectBase arg1) {
}
@Override
public void onRectChanged(RectF arg0, SpenObjectBase arg1) {
}
@Override
public void onObjectChanged(ArrayList<SpenObjectBase> arg0) {
}
@Override
public boolean onMenuSelected(ArrayList<SpenObjectBase> objectList, int itemId) {
SpenObjectContainer objContainer;
SpenObjectBase object = objectList.get(0);
switch (itemId) {
// Properties of object shape/line
case CONTEXT_MENU_PROPERTIES_ID:
shapeProperties();
mSpenSurfaceView.closeControl();
break;
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 153
mSpenPageDoc.ungroupObject((SpenObjectContainer) selectedObj,
false);
}
}
mSpenSurfaceView.closeControl();
mSpenPageDoc.selectObject(objList);
mSpenSurfaceView.update();
break;
return true;
}
@Override
public boolean onCreated(ArrayList<SpenObjectBase> objectList, ArrayList<Rect>
relativeRectList,
ArrayList<SpenContextMenuItemInfo> menu, ArrayList<Integer> styleList, int
pressType, PointF point) {
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 154
}
menu.add(new SpenContextMenuItemInfo(CONTEXT_MENU_DELETE_ID, "Delete", true));
// Display Group menu when more than one object is selected.
if (objectList.size() > 1) {
menu.add(new SpenContextMenuItemInfo(CONTEXT_MENU_GROUP_ID, "Group",
true));
}
// Display Ungroup menu if the selected objects include one or more
// ObjectContainers.
for (SpenObjectBase obj : objectList) {
if (obj.getType() == SpenObjectBase.TYPE_CONTAINER) {
menu.add(new SpenContextMenuItemInfo(CONTEXT_MENU_UNGROUP_ID,
"Ungroup", true));
break;
}
}
// Display Arrange menu if only one object is selected.
if (objectList.size() == 1) {
menu.add(new SpenContextMenuItemInfo(CONTEXT_MENU_MOVE_TO_BOTTOM_ID,
"Bottom", true));
menu.add(new SpenContextMenuItemInfo(CONTEXT_MENU_MOVE_TO_BACKWARD_ID,
"Backward", true));
menu.add(new SpenContextMenuItemInfo(CONTEXT_MENU_MOVE_TO_FORWARD_ID,
"Forward", true));
menu.add(new SpenContextMenuItemInfo(CONTEXT_MENU_MOVE_TO_TOP_ID, "Top",
true));
return true;
}
// Attach an individual control for each object.
SpenControlList controlList = new SpenControlList(mContext, mSpenPageDoc);
controlList.setObject(objectList);
controlList.setGroup(false);
mSpenSurfaceView.setControl(controlList);
controlList.setContextMenu(menu);
return false;
}
@Override
public boolean onClosed(ArrayList<SpenObjectBase> arg0) {
return false;
}
};
.........
The following sections provide more details on the steps involved in moving objects forward and backward.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 155
2. Call SpenSurfaceView.setControlListener()to register the listener.
In the onCreated() callback method,which is called when there is a control in the View area, create a
context menu:
Create an SpenContextMenuItemInfo instance to add the menu items that appear in the context
menu when users select a single object:
o Bottom to move the selected object to the bottom
o "Backward" to move the object one level back
o "Forward" to move the object one level forward
o "Top" to move the object to the top.
Create SpenContextMenuItemInfo to register these commands in the context menu.
public boolean onCreated(ArrayList<SpenObjectBase> objectList, ArrayList<Rect>
relativeRectList, ArrayList<SpenContextMenuItemInfo> menu, ArrayList<Integer>
styleList, int pressType, PointF point) {
.........
1. In the onMenuSelected() callback method, which is called when a menu item is selected from the
context menu on a control, execute the menu items using their menu IDs.
When the Bottom menu item is selected from the context menu, do the following:
Calculate the step that makes the index of the selected object zero. This is the return value of
SpenPageDoc.getObjectIndex(object) with a leading minus sign.
Call SpenPageDoc.moveObjectIndex() and pass the step that was calculated as the second
parameter. If the step is a negative integer, change the index to the start of the object list. If the
step is a positive integer, change the index to the end of the object list.
o Call SpenPageDoc.getObjectIndex() to get the current index of the selected object.
o Call SpenPageDoc.getObjectCount() to get the number of objects in SpenPageDoc.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 156
Call SpenPageDoc.moveObjectIndex() using the calculated step to move the object to the bottom
in SpenPageDoc.
Call SpenSurfaceView.update() to refresh the screen.
public boolean onMenuSelected(ArrayList<SpenObjectBase> objectList, int itemId) {
SpenObjectContainer objContainer;
SpenObjectBase object = objectList.get(0);
switch (itemId) {
.........
Set the step to-1 if the object is not located at the bottom of the stack.Call
SpenPageDoc.moveObjectIndex() to send the object back one level in SpenPageDoc.
Set the step to 1 if the object is not located at the top of the stack. Call
SpenPageDoc.moveObjectIndex() to bring the object forward one level in SpenPageDoc.
When the Top menu item is selected from the context menu, do the following:
Calculate the step that makes the index of the selected object -1 subtracted from the count of all
objects.Call SpenPageDoc.moveObjectIndex() to bring the object to the top in SpenPageDoc.
Call SpenSurfaceView.update() to refresh the screen.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 157
// Bring the selected object to the front.
case CONTEXT_MENU_MOVE_TO_TOP_ID:
mSpenPageDoc.moveObjectIndex(object,
mSpenPageDoc.getObjectCount(true) - 1 -
mSpenPageDoc.getObjectIndex(object), true);
mSpenSurfaceView.update();
break;
You need an SpenObjectRuntimeInfo object or the class name value of an SOR to call
createObjectRuntime(). If the SOR has a private key, the private key should be sent.
Pen SDK provides the following key classes forthe SOR functionality:
Class Description
SpenObjectRuntimeInfo Provides information to make SpenObjectRuntime
available.
Name: The name of ObjectRuntime (String)
className: The class name of ObjectRuntime
(String)
version: Version information for ObjectRuntime
(Integer)
iconImageURI: The path to the icon image
(String)
hasPrivateKey: Whether a private key exists or
not (boolean)
SpenObjectRuntime Provides functions that manipulate SpenObjectRuntime.
Prior to using the SpenObjectRuntime class, you should
create an instance using ObjectRuntimeManager.
SpenObjectRuntimeManager Manages instances of SpenObjectRuntime.
You can use SpenObjectRuntimeManager to create or
delete an instance of SpenObjectRuntime.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 158
4.4.1. Adding Video Objects
The sample application implements the following features:
private finalintCONTEXT_MENU_RUN_ID = 0;
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 159
private ImageView mSelectionBtn;
private ImageView mPenBtn;
private ImageView mVideoBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sor);
mContext = this;
mActivity = this;
// Initialize Pen.
isSpenFeatureEnabled =
spenPackage.isFeatureEnabled(Spen.DEVICE_PEN);
} catch (SsdkUnsupportedException e) {
if( SDKUtils.processUnsupportedException(this, e) == true) {
return;
}
} catch (Exception e1) {
Toast.makeText(mContext, "Cannot initialize Pen.",
Toast.LENGTH_SHORT).show();
e1.printStackTrace();
finish();
}
mSpenViewLayout =
(RelativeLayout) findViewById(R.id.spenViewLayout);
// Create PenView.
mSpenSurfaceView = new SpenSurfaceView(mContext);
if (mSpenSurfaceView == null) {
Toast.makeText(mContext, "Cannot create new SpenSurfaceView.",
Toast.LENGTH_SHORT).show();
finish();
}
mSpenSurfaceView.setZoomable(false);
mSpenViewLayout.addView(mSpenSurfaceView);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 160
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();
}
// Add a page to NoteDoc and then get the instance to use as an input
// variable.
mSpenPageDoc = mSpenNoteDoc.appendPage();
mSpenPageDoc.setBackgroundColor(0xFFD6E6F5);
mSpenPageDoc.clearHistory();
// Set PageDoc in the View.
mSpenSurfaceView.setPageDoc(mSpenPageDoc, true);
initPenSettingInfo();
// Register a listener.
mSpenSurfaceView.setControlListener(mControlListener);
selectButton(mPenBtn);
if(isSpenFeatureEnabled == false) {
mToolType = SpenSurfaceView.TOOL_FINGER;
mSpenSurfaceView.setToolTypeAction(mToolType,
SpenSurfaceView.ACTION_STROKE);
Toast.makeText(mContext,
"Device does not support S pen. \n You can draw strokeswith
your finger",
Toast.LENGTH_SHORT).show();
}
}
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 161
private final OnClickListener mSelectionBtnClickListener =
new OnClickListener() {
@Override
public void onClick(View v) {
selectButton(mSelectionBtn);
mSpenSurfaceView.setToolTypeAction(mToolType,
SpenSurfaceView.ACTION_SELECTION);
}
};
@Override
public boolean onCreated(ArrayList<SpenObjectBase> objectList,
ArrayList<Rect> relativeRectList,
ArrayList<SpenContextMenuItemInfo> menu,
ArrayList<Integer> styleList, intpressType, PointF point) {
if (objectList == null) {
return false;
}
// Display the context menu if any SOR information is found.
if (objectList.get(0).getSorInfo() != null) {
menu.add(new SpenContextMenuItemInfo(
CONTEXT_MENU_RUN_ID, "Run", true));
return true;
}
return true;
}
@Override
public boolean onMenuSelected(
ArrayList<SpenObjectBase> objectList, int itemId) {
if (objectList == null) {
return true;
}
if (itemId == CONTEXT_MENU_RUN_ID) {
SpenObjectBase object = objectList.get(0);
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 162
mSpenSurfaceView.getControl().setContextMenuVisible(false);
mSpenSurfaceView.getControl().
setStyle(SpenControlBase.STYLE_BORDER_STATIC);
mSpenSurfaceView.update();
}
return false;
}
@Override
public void onObjectChanged(ArrayList<SpenObjectBase> object) {
}
@Override
public void onRectChanged(RectF rect, SpenObjectBase object) {
}
@Override
public void onRotationChanged(float angle,
SpenObjectBase objectBase) {
}
@Override
public boolean onClosed(ArrayList<SpenObjectBase> objectList) {
if(mVideoRuntime != null)
mVideoRuntime.stop(true);
return false;
}
};
void createObjectRuntime() {
if (mSpenObjectRuntimeInfoList == null
|| mSpenObjectRuntimeInfoList.size() == 0) {
return;
}
try {
for(SpenObjectRuntimeInfo info : mSpenObjectRuntimeInfoList) {
if (info.name.equalsIgnoreCase("Video")) {
mVideoRuntime =
mSpenObjectRuntimeManager.createObjectRuntime(info);
mObjectRuntimeInfo = info;
startObjectRuntime();
return;
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
Toast.makeText(mContext, "ObjectRuntimeInfo class not found.",
Toast.LENGTH_SHORT).show();
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 163
} catch (InstantiationException e) {
e.printStackTrace();
Toast.makeText(mContext,
"Failed to access the ObjectRuntimeInfo constructor.",
Toast.LENGTH_SHORT).show();
} catch (IllegalAccessException e) {
e.printStackTrace();
Toast.makeText(mContext,
"Failed to access the ObjectRuntimeInfo field or method.",
Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(mContext, "ObjectRuntimeInfo is not loaded.",
Toast.LENGTH_SHORT).show();
}
}
void startObjectRuntime() {
if (mVideoRuntime == null) {
Toast.makeText(mContext,
"ObjectRuntime is not loaded \n Load Plug-in First !!",
Toast.LENGTH_SHORT).show();
return;
}
if(objectBase == null) {
Toast.makeText(mContext, "Has no selected object.",
Toast.LENGTH_SHORT).show();
return;
}
objectBase.setSorInfo(mObjectRuntimeInfo.className);
objectBase.setOutOfViewEnabled(false);
mVideoRuntime.setListener(objectRuntimelistener);
mSpenPageDoc.appendObject(objectBase);
mSpenPageDoc.selectObject(objectBase);
mSpenSurfaceView.update();
mSpenSurfaceView.getControl().setContextMenuVisible(false);
mVideoRuntime.start(objectBase,
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 164
new RectF(0, 0, mSpenPageDoc.getWidth(), mSpenPageDoc.getHeight()),
mSpenSurfaceView.getPan(), mSpenSurfaceView.getZoomRatio(),
mSpenSurfaceView.getFrameStartPosition(), mSpenViewLayout);
SpenObjectRuntime.UpdateListener objectRuntimelistener =
new SpenObjectRuntime.UpdateListener() {
@Override
public void onCompleted(Object objectBase) {
if ( mSpenSurfaceView != null ) {
SpenControlBase control = mSpenSurfaceView.getControl();
if (control != null) {
control.setContextMenuVisible(true);
mSpenSurfaceView.updateScreenFrameBuffer();
mSpenSurfaceView.update();
}
}
mVideoBtn.setClickable(true);
}
@Override
public void onObjectUpdated(RectF rect, Object objectBase) {
if ( mSpenSurfaceView != null ) {
SpenControlBase control = mSpenSurfaceView.getControl();
if(control != null) {
control.fit();
control.invalidate();
mSpenSurfaceView.update();
}
}
}
@Override
public void onCanceled(int state, Object objectBase) {
if (state == SpenObjectRuntimeInterface.CANCEL_STATE_INSERT) {
mSpenPageDoc.removeObject((SpenObjectBase) objectBase);
mSpenPageDoc.removeSelectedObject();
mSpenSurfaceView.closeControl();
mSpenSurfaceView.update();
} else if (state == SpenObjectRuntimeInterface.CANCEL_STATE_RUN) {
mSpenSurfaceView.closeControl();
mSpenSurfaceView.update();
}
mVideoBtn.setClickable(true);
}
};
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 165
float zoom = mSpenSurfaceView.getZoomRatio();
PointF startPoint = mSpenSurfaceView.getFrameStartPosition();
RectF realRect = new RectF();
realRect.set(
(rect.left - panX) * zoom + startPoint.x,
(rect.top - panY) * zoom + startPoint.y,
(rect.right - panX) * zoom + startPoint.x,
(rect.bottom - panY) * zoom + startPoint.y
);
return realRect;
}
@Override
protected void onDestroy() {
super.onDestroy();
if(mSpenObjectRuntimeManager != null) {
if(mVideoRuntime != null) {
mVideoRuntime.stop(true);
mSpenObjectRuntimeManager.unload(mVideoRuntime);
}
mSpenObjectRuntimeManager.close();
}
if(mSpenSurfaceView != null) {
mSpenSurfaceView.close();
mSpenSurfaceView = null;
}
if(mSpenNoteDoc != null) {
try {
mSpenNoteDoc.close();
} catch (Exception e) {
e.printStackTrace();
}
mSpenNoteDoc = null;
}
}
}
The following sections provide more details on the steps involved in working with SORs.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 166
new ArrayList<SpenObjectRuntimeInfo>();
mSpenObjectRuntimeInfoList = mSpenObjectRuntimeManager.getObjectRuntimeInfoList();
Create an OnClickListener listener instance for the Insert Video button, mVideoBtnClickListener in the
sample, and register it by callingsetOnClickListener()on the button.
In the onClick() method, get the SOR information for Video from the list of SOR objects acquired when
you initialized your application.
.........
void createObjectRuntime() {
if (mSpenObjectRuntimeInfoList == null
|| mSpenObjectRuntimeInfoList.size() == 0) {
return;
}
try {
for(SpenObjectRuntimeInfo info : mSpenObjectRuntimeInfoList) {
if (info.name.equalsIgnoreCase("Video")) {
mVideoRuntime =
mSpenObjectRuntimeManager.createObjectRuntime(info);
mObjectRuntimeInfo = info;
startObjectRuntime();
return;
}
}
} catch (ClassNotFoundException e) {
.........
} catch (InstantiationException e) {
.........
} catch (IllegalAccessException e) {
.........
} catch (Exception e) {
.........
}
}
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 167
The SOR type for video is SpenObjectRuntimeInterface.TYPE_IMAGE.Create an image object for the SOR,
and set the SOR information to the image object by calling SpenObjectBase.setSorInfo().
Create and register an SpenControlListener listener instance for the SOR events and call the following
methods:
void startObjectRuntime() {
if (mVideoRuntime == null) {
Toast.makeText(mContext,
"ObjectRuntime is not loaded \n Load Plug-in First !!",
Toast.LENGTH_SHORT).show();
return;
}
objectBase.setSorInfo(mObjectRuntimeInfo.className);
objectBase.setOutOfViewEnabled(false);
mVideoRuntime.setListener(objectRuntimelistener);
mSpenPageDoc.appendObject(objectBase);
mSpenPageDoc.selectObject(objectBase);
mSpenSurfaceView.update();
mSpenSurfaceView.getControl().setContextMenuVisible(false);
mVideoRuntime.start(objectBase,
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 168
new RectF(0, 0, mSpenPageDoc.getWidth(), mSpenPageDoc.getHeight()),
mSpenSurfaceView.getPan(), mSpenSurfaceView.getZoomRatio(),
mSpenSurfaceView.getFrameStartPosition(), mSpenViewLayout);
In the onCreated() callback method, which is called when there is a control in the View area, add a Run
menu item to the context menu that appears when the selected object contains SOR information.
1. In the onMenuSelected() callback method, which is called when a menu item is selected from the
context menu in a control, do the following:
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 169
public boolean onMenuSelected(
ArrayList<SpenObjectBase> objectList, int itemId) {
if (objectList == null) {
return true;
}
if (itemId == CONTEXT_MENU_RUN_ID) {
SpenObjectBase object = objectList.get(0);
mSpenSurfaceView.getControl().setContextMenuVisible(false);
mSpenSurfaceView.getControl().setStyle(SpenControlBase.STYLE_BORDER_STATIC);
mSpenSurfaceView.update();
}
return false;
}
In the onCompleted() callback method, which is called when the SOR is done, call the following methods:
In the onCanceled() callback method,which is called for cancellation events, do the following:
When an event to cancel the registrationof a new SOR occurs, delete the corresponding object
from SpenPageDoc, close the control, and refresh the screen.
When an event to cancel an SOR action occurs, close the control and refresh the screen.
SpenObjectRuntime.UpdateListener objectRuntimelistener =
new SpenObjectRuntime.UpdateListener() {
@Override
public void onCompleted(Object objectBase) {
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 170
if ( mSpenSurfaceView != null ) {
SpenControlBase control = mSpenSurfaceView.getControl();
if (control != null) {
control.setContextMenuVisible(true);
mSpenSurfaceView.updateScreenFrameBuffer();
mSpenSurfaceView.update();
}
}
mVideoBtn.setClickable(true);
}
@Override
public void onObjectUpdated(RectF rect, Object objectBase) {
if ( mSpenSurfaceView != null ) {
SpenControlBase control = mSpenSurfaceView.getControl();
if(control != null) {
control.fit();
control.invalidate();
mSpenSurfaceView.update();
}
}
}
@Override
public void onCanceled(int state, Object objectBase) {
if (state == SpenObjectRuntimeInterface.CANCEL_STATE_INSERT) {
mSpenPageDoc.removeObject((SpenObjectBase) objectBase);
mSpenPageDoc.removeSelectedObject();
mSpenSurfaceView.closeControl();
mSpenSurfaceView.update();
} else if (state == SpenObjectRuntimeInterface.CANCEL_STATE_RUN) {
mSpenSurfaceView.closeControl();
mSpenSurfaceView.update();
}
mVideoBtn.setClickable(true);
}
};
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 171
Figure 28: SOR list
.........
selectButton(mPenBtn);
// Set up ObjectRuntimeManager.
mSpenObjectRuntimeManager = new SpenObjectRuntimeManager(mActivity);
mSpenObjectRuntimeInfoList =
new ArrayList<SpenObjectRuntimeInfo>();
mSpenObjectRuntimeInfoList = mSpenObjectRuntimeManager.getObjectRuntimeInfoList();
.........
.........
void createObjectRuntime() {
if (mSpenObjectRuntimeInfoList == null
|| mSpenObjectRuntimeInfoList.size() == 0) {
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 172
return;
}
new AlertDialog.Builder(mContext)
.setTitle("Select Object Runtime")
.setItems(objectRuntimeInfoList, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
try {
SpenObjectRuntimeInfo info =
mSpenObjectRuntimeInfoList.get(which);
mObjectRuntime =
mSpenObjectRuntimeManager.createObjectRuntime(info);
mObjectRuntimeInfo = info;
startObjectRuntime();
return;
} catch (ClassNotFoundException e) {
e.printStackTrace();
Toast.makeText(mContext, "ObjectRuntimeInfo class not found.",
Toast.LENGTH_SHORT).show();
} catch (InstantiationException e) {
e.printStackTrace();
Toast.makeText(mContext,
"Failed to access the ObjectRuntimeInfo constructor.",
Toast.LENGTH_SHORT).show();
} catch (IllegalAccessException e) {
e.printStackTrace();
Toast.makeText(mContext,
"Failed to access the ObjectRuntimeInfo field or method.",
Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(mContext, "ObjectRuntimeInfo is not loaded.",
Toast.LENGTH_SHORT).show();
}
}
}).show();
}
.........
The following sections provide more details on the steps involved in working with SOR lists.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 173
4.4.2.1 Showing SOR Lists
To show an SOR list in your application:
1. In theonCreate() method,
create an SpenObjectRuntimeManager instance to call
getObjectRuntimeInfoList() to get the list of available SpenObjectRuntime objects.
2. Extract the SOR names from the list to create a dialog showing the names in a list.
In the onClick() callback method,which is called when users select an SOR, get the
SpenObjectRuntimeInfo of the selected object. Call
mSpenObjectRuntimeManager.createObjectRuntime()and pass the information to create the selected
SOR.
new AlertDialog.Builder(mContext)
.setTitle("Select Object Runtime")
.setItems(objectRuntimeInfoList, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
try {
SpenObjectRuntimeInfo info =
mSpenObjectRuntimeInfoList.get(which);
mObjectRuntime =
mSpenObjectRuntimeManager.createObjectRuntime(info);
Smart Scroll
Smart Zoom
Translucent View
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 174
Smart Scroll button for turning Smart Scroll on and off.
Listener for button click events.
Hover zone where Smart Scroll is available.
Enabling and disabling horizontal and vertical scrolling.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_smart_scroll);
mContext = this;
// Initialize Pen.
.
boolean isSpenFeatureEnabled = false;
Spen spenPackage = new Spen();
try {
spenPackage.initialize(this);
isSpenFeatureEnabled =
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 175
spenPackage.isFeatureEnabled(Spen.DEVICE_PEN);
} catch (SsdkUnsupportedException e) {
if( SDKUtils.processUnsupportedException(this, e) == true) {
return;
}
} catch (Exception e1) {
Toast.makeText(mContext, "Cannot initialize Pen.",
Toast.LENGTH_SHORT).show();
e1.printStackTrace();
finish();
}
RelativeLayout spenViewLayout =
(RelativeLayout) findViewById(R.id.spenViewLayout);
// Create PenView.
mSpenSurfaceView = new SpenSurfaceView(mContext);
if (mSpenSurfaceView == null) {
Toast.makeText(mContext, "Cannot create new SpenSurfaceView.",
Toast.LENGTH_SHORT).show();
finish();
}
spenViewLayout.addView(mSpenSurfaceView);
initPenSettingInfo();
if(isSpenFeatureEnabled == false) {
mSpenSurfaceView.setToolTypeAction(SpenSurfaceView.TOOL_FINGER,
SpenSurfaceView.ACTION_STROKE);
Toast.makeText(mContext,
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 176
"Device does not support S pen. \n You can draw strokeswith
your finger",
Toast.LENGTH_SHORT).show();
}
setSmartScroll(isSmartScrollEnabled);
}
};
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if(mSmartScrollBtn.isSelected() == false) {
return;
}
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 177
@SuppressLint("NewApi")
@SuppressWarnings("deprecation")
@Override
public void onGlobalLayout() {
setSmartScroll(true);
if (Build.VERSION.SDK_INT>= 16) {
mSpenSurfaceView.getViewTreeObserver().
removeOnGlobalLayoutListener(this);
} else {
// This method was deprecated in API level 16.
mSpenSurfaceView.getViewTreeObserver().
removeGlobalOnLayoutListener (this);
}
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
if(mSpenSurfaceView != null) {
mSpenSurfaceView.close();
mSpenSurfaceView = null;
}
if(mSpenNoteDoc != null) {
try {
mSpenNoteDoc.close();
} catch (Exception e) {
e.printStackTrace();
}
mSpenNoteDoc = null;
}
}
}
The following sections provide more details on the steps involved in adding Smart Scroll to your application.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 178
3. In the onClick() method, call SpenSurfaceView.isVerticalSmartScrollEnabled() to check if
vertical Smart Scroll is enabled. You can enable or disable the button by using the logical NOT
operator (!) with the return value of isVerticalSmartScrollEnabled() to enable or disable
vertical and horizontal scrolling when users click the button.
Set the region where Smart Scroll is available. Typically, Pen SDK enables Smart Scroll when it generates a
hovering event in the 10% of the width from the left or right edge and 10% of the width from the top or
bottom edge.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 179
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if(mSmartScrollBtn.isSelected() == false) {
return;
}
@SuppressLint("NewApi")
@SuppressWarnings("deprecation")
@Override
public void onGlobalLayout() {
setSmartScroll(true);
if (Build.VERSION.SDK_INT>= 16) {
mSpenSurfaceView.getViewTreeObserver().
removeOnGlobalLayoutListener(this);
} else {
// This method was deprecated in API level 16.
mSpenSurfaceView.getViewTreeObserver().
removeGlobalOnLayoutListener (this);
}
}
});
}
Smart Zoom button to zoom in when a S pen hovers over the specified Smart Zoom region.
Listener for button click events.
Enabling and disabling Smart Zoom when the button is clicked.
Setting the Smart Zoom region.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 180
Figure 30: Smart Zoom
.........
.........
.........
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 181
@Override
public void onClick(View v) {
boolean isSmartScaleEnabled =
!mSpenSurfaceView.isSmartScaleEnabled();
mSmartZoomBtn.setSelected(isSmartScaleEnabled);
setSmartScale(isSmartScaleEnabled);
}
};
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if(mSmartScrollBtn.isSelected() == false
&&mSmartZoomBtn.isSelected() == false) {
return;
}
@SuppressLint("NewApi")
@SuppressWarnings("deprecation")
@Override
public void onGlobalLayout() {
if(mSmartScrollBtn.isSelected() == true) {
setSmartScroll(true);
}
if(mSmartZoomBtn.isSelected() == true){
setSmartScale(true);
}
if (Build.VERSION.SDK_INT>= 16) {
mSpenSurfaceView.getViewTreeObserver().
removeOnGlobalLayoutListener(this);
} else {
// This method was deprecated in API level 16.
mSpenSurfaceView.getViewTreeObserver().
removeGlobalOnLayoutListener (this);
}
}
});
}
.........
The following sections provide more details on the steps involved in adding Smart Zoom to your application.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 182
2. Create an OnClickListener listener instance for the Smart Zoom button,
mSmartZoomBtnClickListener in the sample, and register it by calling setOnClickListener()
onthe button.
Set the region where Smart Zoom is available. The sample application enables Smart Zoom when it
generates a hover event outside the 10% of the width from the left or right edge and 10% of the width from
the top or bottom edge.
// Set SmartScale.
Rect zoomRegion = new Rect(w1, h1, w9, h9);
mSpenSurfaceView.setSmartScaleEnabled(enable,zoomRegion, 8, 500, 1.5f);
Simple View button for creating anSpenSimpleView instance with a transparent background.
Stroke creation andsavingin an image file with a specified name.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 183
Figure 31: Simple View
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_simple_view);
mContext = this;
.........
.........
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 184
mSimpleViewBtn.setOnClickListener(mSimpleViewBtnClickListener);
}
if (file.exists() == true) {
return;
}
try {
file.createNewFile();
out = new FileOutputStream(file);
if (strFilePath.endsWith(".jpg")) {
bitmap.compress(CompressFormat.JPEG, 100, out);
} else {
bitmap.compress(CompressFormat.PNG, 100, out);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(out!= null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
.........
mSpenSimpleViewContainer =
(RelativeLayout) findViewById(R.id.spenSimpleViewContainer);
mSpenSimpleViewContainer.setVisibility(View.VISIBLE);
RelativeLayout spenSimpleViewLayout =
(RelativeLayout) findViewById(R.id.spenSimpleViewLayout);
FrameLayout.LayoutParams simpleViewContainerParams =
(FrameLayout.LayoutParams)
mSpenSimpleViewContainer.getLayoutParams();
FrameLayout.LayoutParams simpleViewLayoutParams =
(FrameLayout.LayoutParams)
spenSimpleViewLayout.getLayoutParams();
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 185
Rect rect = new Rect();
display.getRectSize(rect);
int btnHeight = 100;
// Resize SimpleView to the width of the screen at a random ratio.
if (rect.width() > rect.height()) {
simpleViewContainerParams.width = (int) (rect.height() * .6);
simpleViewContainerParams.height =
(int) (rect.height() * .6) + btnHeight;
} else {
simpleViewContainerParams.width = (int) (rect.width() * .6);
simpleViewContainerParams.height =
(int) (rect.width() * .6) + btnHeight;
}
simpleViewLayoutParams.width =
(int) (simpleViewContainerParams.width * .9);
simpleViewLayoutParams.height =
(int) ((simpleViewContainerParams.height)
- (simpleViewContainerParams.width * .1) - btnHeight);
mSpenSimpleViewContainer.setLayoutParams(simpleViewContainerParams);
spenSimpleViewLayout.setLayoutParams(simpleViewLayoutParams);
initSimpleViewPenSettingInfo();
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 186
penInfo.size = 10;
mSpenSimpleView.setPenSettingInfo(penInfo);
}
AlertDialog.Builder builderSave =
new AlertDialog.Builder(mContext);
builderSave.setTitle("Enter file name");
builderSave.setView(layout);
builderSave.setPositiveButton("OK",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
closeSimpleView();
}
}
});
builderSave.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
dlgSave = builderSave.create();
dlgSave.show();
}
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 187
// Specify the name of the file to be captured.
File fileCacheItem = new File(strFileName);
// Capture and save Bitmap.
Bitmap imgBitmap = mSpenSimpleView.captureCurrentView();
@Override
protected void onDestroy() {
super.onDestroy();
if(mSpenSimpleView != null) {
mSpenSimpleView.close();
mSpenSimpleView = null;
}
if(mSpenSurfaceView != null) {
mSpenSurfaceView.close();
mSpenSurfaceView = null;
}
if(mSpenNoteDoc != null) {
try {
mSpenNoteDoc.close();
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 188
} catch (Exception e) {
e.printStackTrace();
}
mSpenNoteDoc = null;
}
}
}
The following sections provide more details on the steps involved in adding Simple View to your application.
1. Specify the background image of the main SpenSurfaceView instance to make it easier to
understand the SimpleView functionality.
2. Decode the resource file smemo_bg.jpg and save it into the file folder of the application.
3. Call SpenPageDoc.setBackgroundImage() .
4. Use the BACKGROUND_IMAGE_MODE_STRETCH option to stretch the background image to the full
size of the screen when calling setBackgroundImageMode().
Note
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 189
4.5.3.2 Setting Up Simple View
To handle Simple View button events in your application:
3. In the onClick () method, disable the Simple View button to avoid repeated actions.
mSimpleViewBtn.setEnabled(false);
mSpenSimpleViewContainer = (RelativeLayout) findViewById(R.id.spenSimpleViewContainer);
mSpenSimpleViewContainer.setVisibility(View.VISIBLE);
RelativeLayout spenSimpleViewLayout = (RelativeLayout)
findViewById(R.id.spenSimpleViewLayout);
FrameLayout.LayoutParams simpleViewContainerParams =
(FrameLayout.LayoutParams) mSpenSimpleViewContainer.getLayoutParams();
FrameLayout.LayoutParams simpleViewLayoutParams =
(FrameLayout.LayoutParams) spenSimpleViewLayout.getLayoutParams();
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 190
Create an SpenSimpleView instance with these dimensions and pass it when callingaddView() to connect
the instance with the SimpleViewLayout view and set up the pen for use in SpenSimpleView.
initSimpleViewPenSettingInfo();
In the onClick method, save the image to the SPen/images folder in external storage under the user-
defined name.
Save the bitmap in PNG format and call sendBroadcast() with Intent.ACTION_MEDIA_MOUNTED to
register the new image file in the gallery application.
.........
.........
builderSave.setPositiveButton("OK",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 191
.........
if (!fileName.equals("")) {
saveFilePath += fileName + ".png";
saveImageFile(saveFilePath);
closeSimpleView();
}
.........
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,
Uri.parse("file://"
+ Environment.getExternalStorageDirectory())));
} catch (IOException e) {
e.printStackTrace();
}
}
imgBitmap.recycle();
}
In theonClick() method, enable the Simple View button, hide SimpleViewLayout, and clear the instances
of SpenSimpleView to avoid memory leaks.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 192
Button cancelBtn = (Button) findViewById(R.id.cancel_btn);
cancelBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
closeSimpleView();
return;
}
});
.........
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 193
Figure 32: Temporary Stroke
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_temporary_stroke);
mContext = this;
// Initialize Pen.
boolean isSpenFeatureEnabled = false;
Spen spenPackage = new Spen();
try {
spenPackage.initialize(this);
isSpenFeatureEnabled =
spenPackage.isFeatureEnabled(Spen.DEVICE_PEN);
} catch (SsdkUnsupportedException e) {
if( SDKUtils.processUnsupportedException(this, e) == true) {
return;
}
} catch (Exception e1) {
Toast.makeText(mContext, "Cannot initialize Pen.",
Toast.LENGTH_SHORT).show();
e1.printStackTrace();
finish();
}
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 194
// Create PenView.
RelativeLayout spenViewLayout =
(RelativeLayout) findViewById(R.id.spenViewLayout);
mSpenSurfaceView = new SpenSurfaceView(mContext);
if (mSpenSurfaceView == null) {
Toast.makeText(mContext, "Cannot create new SpenView.",
Toast.LENGTH_SHORT).show();
finish();
}
spenViewLayout.addView(mSpenSurfaceView);
initPenSettingInfo();
// Register the listener.
mSpenSurfaceView.setTouchListener(mPenTouchListener);
mSpenSurfaceView.startTemporaryStroke();
if(isSpenFeatureEnabled == false) {
mSpenSurfaceView.setToolTypeAction(SpenSurfaceView.TOOL_FINGER,
SpenSurfaceView.ACTION_STROKE);
Toast.makeText(mContext,
"Device does not support S pen. \n You can draw strokeswith yourfinger",
Toast.LENGTH_SHORT).show();
}
}
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 195
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// When ACTION_DOWN occurs before mStrokeRunnable is set
// in a queue, the mStrokeRunnable that waits is removed.
if (mStrokeHandler != null) {
mStrokeHandler.removeCallbacks(mStrokeRunnable);
mStrokeHandler = null;
}
break;
case MotionEvent.ACTION_UP:
// Generate Handler to put mStrokeRunnable in a queue when it
// takes 1000 milliseconds after ACTION_UP occurred.
mStrokeHandler = new Handler();
mStrokeHandler.postDelayed(mStrokeRunnable, 1000);
break;
}
return true;
}
};
@Override
protected void onDestroy() {
super.onDestroy();
if (mStrokeHandler != null) {
mStrokeHandler.removeCallbacks(mStrokeRunnable);
mStrokeHandler = null;
}
if(mSpenSurfaceView != null) {
mSpenSurfaceView.close();
mSpenSurfaceView = null;
}
if(mSpenNoteDoc != null) {
try {
mSpenNoteDoc.close();
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 196
} catch (Exception e) {
e.printStackTrace();
}
mSpenNoteDoc = null;
}
};
}
mSpenPageDoc = mSpenNoteDoc.appendPage();
mSpenSurfaceView.setPageDoc(mSpenPageDoc, true);
mSpenSurfaceView.startTemporaryStroke();
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 197
}
1. Call SpenObjectStroke.setRect() to set the position of the stroke data that is fetched by
SpenSurfaceView.getTemporaryStroke() and cut the data in half.
Call SpenPageDoc.appendObject() to register the stroke data as an object of the current page.
if (mStrokeHandler != null) {
mStrokeHandler.removeCallbacks(mStrokeRunnable);
mStrokeHandler = null;
}
if(mSpenSurfaceView != null) {
mSpenSurfaceView.close();
mSpenSurfaceView = null;
}
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 198
if(mSpenNoteDoc != null) {
try {
mSpenNoteDoc.close();
} catch (Exception e) {
e.printStackTrace();
}
mSpenNoteDoc = null;
}
It creates a Pen SDK instance and a Bitmap sized for the viewport.
It links the PenSDK and the view.
@Override
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 199
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Context context = this;
// Initialize Pen.
Spen spenPackage = new Spen();
try {
spenPackage.initialize(this);
} catch (SsdkUnsupportedException e) {
if( SDKUtils.processUnsupportedException(this, e) == true) {
return;
}
} catch (Exception e1) {
Toast.makeText(context, "Cannot initialize Pen.",
Toast.LENGTH_SHORT).show();
e1.printStackTrace();
finish();
}
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
// The pen manager gets the configurations for the pen to set up the pen.
mPenManager = new SpenPenManager(context);
SpenPenInfo penInfo = new SpenPenInfo();
List<SpenPenInfo> penInfoList = mPenManager.getPenInfoList();
for (SpenPenInfo info : penInfoList) {
if(info.name.equalsIgnoreCase("Brush")) {
penInfo = info;
break;
}
}
try {
mPen = mPenManager.createPen(penInfo);
} catch (ClassNotFoundException e) {
Toast.makeText(context, "SpenPenManager class not found.",
Toast.LENGTH_SHORT).show();
e.printStackTrace();
} catch (InstantiationException e) {
Toast.makeText(context,
"Failed to access the SpenPenManager constructor.",
Toast.LENGTH_SHORT).show();
e.printStackTrace();
} catch (IllegalAccessException e) {
Toast.makeText(context,
"Failed to access the SpenPenManager field or method.",
Toast.LENGTH_SHORT).show();
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(context, "SpenPenManager is not loaded.",
Toast.LENGTH_SHORT).show();
}
mPen.setSize(10);
mPen.setColor(Color.BLUE);
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 200
View view = new MyView(context, mScreenSize.width(), mScreenSize.height());
setContentView(view);
}
@Override
public booleanonTouchEvent(MotionEvent event) {
RectF tempRect = new RectF();
// Get the touch event to draw as the pen draws
if (mBitmap != null) {
mBitmap.setPixel(0, 0, 0);
}
mPen.draw(event, tempRect);
invalidate(convertRect(tempRect));
return true;
}
@Override
protected void onDraw(Canvas canvas) {
// Display the bitmap that the pen draws on the canvas.
canvas.drawBitmap(mBitmap, null, bitmapRect, null);
super.onDraw(canvas);
}
return dst;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
mPenManager.destroyPen(mPen);
mBitmap.recycle();
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 201
}
}
Call SpenPenManager.getPenInfoList() to get the list of pen information objects on the available Pen
SDKplug-ins.
Select an appropriate Pen SDK plug-in from the list and call SpenPenManager.createPen() with the
associated pen information object. The sample uses the name Brush to create a Brush SpenPen
instance.
If you know the class name, you can use the full class name to create a pen instance without getting the
pen information. The preloaded class names that you can use are listed below:
Note
PenSDK supports the following pre-loadedpen plug-ins:
Name Value Class Name
InkPen SPEN_INK_PEN com.samsung.android.sdk.pen.pen.preload.InkPen
Pencil SPEN_PENCIL com.samsung.android.sdk.pen.pen.preload.Pencil
Marker SPEN_MARKER com.samsung.android.sdk.pen.pen.preload.Marker
Brush SPEN_BRUSH com.samsung.android.sdk.pen.pen.preload.Brush
ChineseBrush SPEN_CHINESE_BRUSH com.samsung.android.sdk.pen.pen.preload.ChineseBrush
The following sample code shows how to create a pen instance with a class name defined as a static
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 202
Note
variable:
SpenPenManager mPenManager = new SpenPenManager(context);
SpenPen mPen = mPenManager.createPen(SpenPenManager.SPEN_BRUSH);
1. Inherit the Android View class to create a view that displays the object data drawn with finger or
with S pen input.
Call SpenPen.setBitmap() to link the pen plug-in and viewport to enable users to draw objects.
1. In the onTouchEvent()method, call SpenPen.draw() and pass the event.The SpenPen instance
drawsthe objects and getsthe RectF values representing the area where the objects are drawn.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 203
invalidate(convertRect(tempRect));
return true;
}
@Override
protected void onDraw(Canvas canvas) {
// Display the bitmap that the pen draws on the canvas.
canvas.drawBitmap(mBitmap, null, bitmapRect, null);
super.onDraw(canvas);
}
return dst;
}
When the text recognition output is calculated, the sample application replaces the selected stroke
object with the SpenObjectTextBox recognized as a textual component.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 204
Figure 34: Text recognition
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_text_recognition);
mContext = this;
// InitializePen.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 205
isSpenFeatureEnabled =
spenPackage.isFeatureEnabled(Spen.DEVICE_PEN);
} catch (SsdkUnsupportedException e) {
if( SDKUtils.processUnsupportedException(this, e) == true) {
return;
}
} catch (Exception e1) {
Toast.makeText(mContext, "Cannot initialize Pen.",
Toast.LENGTH_SHORT).show();
e1.printStackTrace();
finish();
}
// Create PenView.
mSpenSurfaceView = new SpenSurfaceView(mContext);
if (mSpenSurfaceView == null) {
Toast.makeText(mContext, "Cannot create new SpenSurfaceView.",
Toast.LENGTH_SHORT).show();
finish();
}
mSpenViewLayout.addView(mSpenSurfaceView);
initPenSettingInfo();
// Register the listener.
mSpenSurfaceView.setControlListener(mControlListener);
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 206
selectButton(mPenBtn);
setTextRecognition();
if(isSpenFeatureEnabled == false) {
mSpenSurfaceView.setToolTypeAction(SpenSurfaceView.TOOL_FINGER,
SpenSurfaceView.ACTION_STROKE);
Toast.makeText(mContext,
"Device does not support S pen. \n You can draw strokes
with your finger",
Toast.LENGTH_SHORT).show();
}
}
List<SpenRecognitionInfo> textRecognitionList =
mSpenTextRecognitionManager.getInfoList(
SpenObjectBase.TYPE_STROKE, SpenObjectBase.TYPE_CONTAINER);
try {
if (textRecognitionList.size() > 0) {
for (SpenRecognitionInfo info : textRecognitionList) {
if (info.name.equalsIgnoreCase("SpenText")) {
mTextRecognition = mSpenTextRecognitionManager
.createRecognition(info);
break;
}
}
} else {
finish();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
Toast.makeText(mContext,
"SpenTextRecognitionManager class not found.",
Toast.LENGTH_SHORT).show();
return;
} catch (InstantiationException e) {
e.printStackTrace();
Toast.makeText(mContext,
"Failed to access the SpenTextRecognitionManager constructor.",
Toast.LENGTH_SHORT).show();
return;
} catch (IllegalAccessException e) {
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 207
e.printStackTrace();
Toast.makeText(mContext,
"Failed to access the SpenTextRecognitionManager field or method.",
Toast.LENGTH_SHORT).show();
return;
} catch (SpenCreationFailureException e) {
// End the application if text recognition is not available.
e.printStackTrace();
AlertDialog.Builder ad = new AlertDialog.Builder(this);
ad.setIcon(this.getResources().getDrawable(
android.R.drawable.ic_dialog_alert));
ad.setTitle(this.getResources().getString(R.string.app_name))
.setMessage(
"This device does not support Recognition.")
.setPositiveButton("OK",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
// finish dialog
dialog.dismiss();
finish();
}
}).show();
ad = null;
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(mContext,
"SpenTextRecognitionManager engine not loaded.",
Toast.LENGTH_SHORT).show();
return;
}
try {
mTextRecognition.setResultListener(new ResultListener() {
@Override
public void onResult(List<SpenObjectBase> input,
List<SpenObjectBase> output) {
// Set rect that will draw text recognized by calculating the
// rect ranges of the selected objects, and purge the selected
// objects and append the recognized object to pageDoc.
RectF rect = new RectF(mScreenRect.width(),
mScreenRect.height(), 0, 0);
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 208
? rect.left : objRect.left;
rect.top = rect.top< objRect.top
? rect.top : objRect.top;
rect.right = rect.right> objRect.right
? rect.right : objRect.right;
rect.bottom = rect.bottom> objRect.bottom
? rect.bottom : objRect.bottom;
}
mSpenPageDoc.removeObject(obj);
}
@Override
public booleanonCreated(ArrayList<SpenObjectBase> selectedList,
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 209
ArrayList<Rect> arg1,
ArrayList<SpenContextMenuItemInfo> arg2,
ArrayList<Integer> arg3, int arg4, PointF arg5) {
if (selectedList.size() > 0 && !mIsProcessingRecognition) {
// Incorporate the selected stroke object into the list and
// send it as a request.
ArrayList<SpenObjectBase> inputList = new
ArrayList<SpenObjectBase>();
for (int i = 0; i < selectedList.size(); i++) {
if (selectedList.get(i).getType() == SpenObjectBase.TYPE_STROKE) {
inputList.add(selectedList.get(i));
}
}
if (inputList.size() <= 0) {
return false;
}
mIsProcessingRecognition = true;
try {
mTextRecognition.request(inputList);
} catch (IllegalStateException e) {
e.printStackTrace();
Toast.makeText(mContext,
"SpenTextRecognition is not loaded.",
Toast.LENGTH_SHORT).show();
return false;
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(mContext,
"SpenTextRecognition engine not loaded.",
Toast.LENGTH_SHORT).show();
return false;
}
return true;
}
return false;
}
@Override
public booleanonClosed(ArrayList<SpenObjectBase> arg0) {
return false;
}
@Override
public boolean onMenuSelected(ArrayList<SpenObjectBase> arg0,
int arg1) {
return false;
}
@Override
public void onObjectChanged(ArrayList<SpenObjectBase> arg0) {
}
@Override
public void onRectChanged(RectF arg0, SpenObjectBase arg1) {
}
@Override
public void onRotationChanged(float arg0, SpenObjectBase arg1) {
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 210
}
};
@Override
protected void onDestroy() {
super.onDestroy();
if (mTextRecognition != null) {
mSpenTextRecognitionManager.destroyRecognition(mTextRecognition);
mSpenTextRecognitionManager.close();
}
if(mSpenSurfaceView != null) {
mSpenSurfaceView.closeControl();
mSpenSurfaceView.close();
mSpenSurfaceView = null;
}
if(mSpenNoteDoc != null) {
try {
mSpenNoteDoc.close();
} catch (Exception e) {
e.printStackTrace();
}
mSpenNoteDoc = null;
}
}
}
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 211
Call SpenTextRecognition.setLanguage() and pass a supported language to the text recognition plug-in
for text recognition.
List<SpenRecognitionInfo> textRecognitionList =
mSpenTextRecognitionManager.getInfoList(
SpenObjectBase.TYPE_STROKE, SpenObjectBase.TYPE_CONTAINER);
try {
if (textRecognitionList.size() > 0) {
for (SpenRecognitionInfo info : textRecognitionList) {
if (info.name.equalsIgnoreCase("SpenText")) {
mTextRecognition = mSpenTextRecognitionManager
.createRecognition(info);
break;
}
}
} else {
finish();
}
} catch (ClassNotFoundException e) {
} catch (InstantiationException e) {
} catch (IllegalAccessException e) {
} catch (SpenCreationFailureException e) {;
}
2. Create an OnClickListener instance for the Insert Stroke button, mPenBtnClickListener in the
sample, and register it by calling setOnClickListener() on the button.
In the onClick()method of the Insert Stroke button, indicate that the button is selected and set
mToolTypeto ACTION_STROKE .
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 212
SpenSurfaceView.ACTION_STROKE);
}
};
In theonClick()method of the Selection button, setmToolTypeto ACTION_SELECTION and indicate that the
button is selected.
1. Create a control event listener for stroke object selection in SpenSurfaceView and register it by
calling SpenSurfaceView.setControlListener() .
Set isProcessingRecognition to true to avoid duplicate requests while the text is being recognized.
@Override
public boolean onCreated(ArrayList<SpenObjectBase> selectedList,
ArrayList<Rect> arg1,
ArrayList<SpenContextMenuItemInfo> arg2,
ArrayList<Integer> arg3, int arg4, PointF arg5) {
if (selectedList.size() > 0 && !mIsProcessingRecognition) {
// Incorporate the selected stroke object into the list and
// send it as a request.
ArrayList<SpenObjectBase> inputList = new ArrayList<SpenObjectBase>();
for (int i = 0; i < selectedList.size(); i++) {
if (selectedList.get(i).getType() == SpenObjectBase.TYPE_STROKE) {
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 213
inputList.add(selectedList.get(i));
}
}
if (inputList.size() <= 0) {
return false;
}
mIsProcessingRecognition = true;
try {
mTextRecognition.request(inputList);
} catch (IllegalStateException e) {
} catch (Exception e) {
}
return true;
}
return false;
}
1. Create a ResultListener instance for text recognition events and register it by calling
SpenTextRecognition.setResultListener ().
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 214
rect.left = rect.left< objRect.left
? rect.left : objRect.left;
rect.top = rect.top< objRect.top
? rect.top : objRect.top;
rect.right = rect.right> objRect.right
? rect.right : objRect.right;
rect.bottom = rect.bottom> objRect.bottom
? rect.bottom : objRect.bottom;
}
mSpenPageDoc.removeObject(obj);
}
1. Call SpenTextRecognitionManager.destroyRecognition()
andSpenTextRecognitionManager.close() to unload the text recognition plug-in
if (mTextRecognition != null) {
mSpenTextRecognitionManager.destroyRecognition(mTextRecognition);
mSpenTextRecognitionManager.close();
}
if(mSpenSurfaceView != null) {
mSpenSurfaceView.closeControl();
mSpenSurfaceView.close();
mSpenSurfaceView = null;
}
if(mSpenNoteDoc != null) {
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 215
try {
mSpenNoteDoc.close();
} catch (Exception e) {
e.printStackTrace();
}
mSpenNoteDoc = null;
}
}
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 216
Figure 35: Signature registration
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 217
private SpenSignatureVerificationManager mSpenSignatureVerificationManager;
private SpenSignatureVerification mSpenSignatureVerification;
public ListAdapter mSignatureAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_signature);
mContext = this;
// Initialize Pen.
Spen spenPackage = new Spen();
try {
spenPackage.initialize(this);
} catch (SsdkUnsupportedException e) {
if( SDKUtils.processUnsupportedException(this, e) == true) {
return;
}
} catch (Exception e1) {
Toast.makeText(mContext, "Cannot initialize Pen.",
Toast.LENGTH_SHORT).show();
e1.printStackTrace();
finish();
}
// Set list
mSignatureListItem = new ArrayList<ListItem>();
mSignatureListItem.add(new ListItem("[Check signature]",
"Check whether the registered signature exists or not"));
mSignatureListItem.add(new ListItem("[Registration]",
"Start registration"));
mSignatureListItem.add(new ListItem("[Verification]",
"Start verification - Signature must be registered"));
mSignatureListItem.add(new ListItem("[Delete signature]",
"Delete the registered signature"));
// Set Verification
mSpenSignatureVerificationManager =
new SpenSignatureVerificationManager(mContext);
List<SpenSignatureVerificationInfo> signatureVerificationList =
mSpenSignatureVerificationManager.getInfoList();
try {
if (signatureVerificationList.size() > 0) {
for (SpenSignatureVerificationInfo info : signatureVerificationList) {
if (info.name.equalsIgnoreCase("NRRSignature")) {
mSpenSignatureVerification = mSpenSignatureVerificationManager
.createSignatureVerification(info);
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 218
break;
}
}
} else {
finish();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
Toast.makeText(mContext,
"SpenSignatureVerificationManager class not found.",
Toast.LENGTH_SHORT).show();
return;
} catch (InstantiationException e) {
e.printStackTrace();
Toast.makeText(mContext,
"Failed to access the SpenSignatureVerificationManager constructor.",
Toast.LENGTH_SHORT).show();
return;
} catch (IllegalAccessException e) {
e.printStackTrace();
Toast.makeText(mContext,
"Failed to access the SpenSignatureVerificationManager field or method.",
Toast.LENGTH_SHORT).show();
return;
} catch (SpenCreationFailureException e) {
// End the application unless the application supports
// verification.
e.printStackTrace();
AlertDialog.Builder ad = new AlertDialog.Builder(this);
ad.setIcon(this.getResources().getDrawable(
android.R.drawable.ic_dialog_alert));
ad.setTitle(this.getResources().getString(R.string.app_name))
.setMessage(
"This device does not support Signature Recognition.")
.setPositiveButton("OK",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
// finish dialog
dialog.dismiss();
finish();
}
}).show();
ad = null;
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(mContext,
"SpenSignatureVerificationManager engine not loaded.",
Toast.LENGTH_SHORT).show();
return;
}
mSignatureList.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
int registeredCount = mSpenSignatureVerification.getRegisteredCount();
int minimumRequiredCount =
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 219
mSpenSignatureVerification.getMinimumRequiredCount();
if (position == LIST_CHECK_SIGNATURE) {
// Check whether any signature is registered or not.
if (registeredCount == minimumRequiredCount)
Toast.makeText(mContext, "Registered signatures exist.",
Toast.LENGTH_SHORT).show();
else
Toast.makeText(mContext,
"Registered Signature is less than minimum required count.",
Toast.LENGTH_SHORT).show();
} else if (position == LIST_REGISRTATION) {
// Go to the Registration menu
Intent intent = new Intent(PenSample5_7_Signature.this,
PenSample5_7_SignatureRegistration.class);
startActivity(intent); // create RegistrationActivity
} else if (position == LIST_VERIFICATION) {
// Go to the Verification menu if any signature is found.
if (registeredCount == minimumRequiredCount) {
Intent intent = new Intent(PenSample5_7_Signature.this,
PenSample5_7_SignatureVerification.class);
startActivity(intent);
} else
Toast.makeText(mContext,
"Registered Signature is less than minimum required count.",
Toast.LENGTH_SHORT).show();
} else if (position == LIST_DELETE_SIGNATURE) {
// Delete the registered signature.
if (registeredCount == 0) {
Toast.makeText(mContext, "Signature is not registered.",
Toast.LENGTH_SHORT).show();
} else {
mSpenSignatureVerification.unregisterAll();
if (mSpenSignatureVerification.getRegisteredCount() == 0)
Toast.makeText(mContext,
"Registered signature is deleted.",
Toast.LENGTH_SHORT).show();
}
}
mSignatureAdapter.notifyDataSetChanged();
}
});
}
class ListItem {
ListItem(String iTitle, String isubTitle) {
Title = iTitle;
subTitle = isubTitle;
}
String Title;
String subTitle;
}
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 220
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public int getCount() {
returnmSignatureListItem.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView,
ViewGroup parent) {
if (convertView == null) {
convertView =
Inflater.inflate(R.layout.signature_list_item, parent,
false);
}
TextView title = (TextView) convertView
.findViewById(R.id.signature_list_title);
title.setText(mSignatureListItem.get(position).Title);
TextView subtitle = (TextView) convertView
.findViewById(R.id.signature_list_subtitle);
subtitle.setText(mSignatureListItem.get(position).subTitle);
if ((position == LIST_VERIFICATION || position == LIST_DELETE_SIGNATURE)
&&mSpenSignatureVerification.getRegisteredCount()
!= mSpenSignatureVerification
.getMinimumRequiredCount()) {
title.setTextColor(0xFF005D87);
subtitle.setTextColor(0xFF777777);
} else {
title.setTextColor(0xFF00B8FF);
subtitle.setTextColor(0xFFFFFFFF);
}
return convertView;
}
}
@Override
protected void onResume() {
if(mSignatureAdapter != null) {
mSignatureAdapter.notifyDataSetChanged();
}
mSignatureAdapter.notifyDataSetChanged();
super.onResume();
}
@Override
protected void onDestroy() {
super.onDestroy();
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 221
if (mSpenSignatureVerification != null) {
mSpenSignatureVerificationManager
.destroySignatureVerification(mSpenSignatureVerification);
mSpenSignatureVerificationManager.close();
}
}
}
public intmSignatureRegistrationNum = 0;
public intmSignatureRegistrationNumMax;
public ListView mSignatureList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_signature_registration);
mContext = this;
// Initialize Pen.
isSpenFeatureEnabled =
spenPackage.isFeatureEnabled(Spen.DEVICE_PEN);
} catch (SsdkUnsupportedException e) {
if( SDKUtils.processUnsupportedException(this, e) == true) {
return;
}
} catch (Exception e1) {
Toast.makeText(mContext, "Cannot initialize Pen.",
Toast.LENGTH_SHORT).show();
e1.printStackTrace();
finish();
}
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 222
// Create PenView.
RelativeLayout spenViewLayout =
(RelativeLayout) findViewById(R.id.spenViewLayout);
mSpenSurfaceView = new SpenSurfaceView(mContext);
if (mSpenSurfaceView == null) {
Toast.makeText(mContext, "Cannot create new SpenView.",
Toast.LENGTH_SHORT).show();
finish();
}
spenViewLayout.addView(mSpenSurfaceView);
if(isSpenFeatureEnabled == false) {
mSpenSurfaceView.setToolTypeAction(SpenSurfaceView.TOOL_FINGER,
SpenSurfaceView.ACTION_STROKE);
Toast.makeText(mContext,
"Device does not support S pen. \n You can draw strokes
with your finger",
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 223
Toast.LENGTH_SHORT).show();
}
// Set Verification
mSpenSignatureVerificationManager =
new SpenSignatureVerificationManager(mContext);
List<SpenSignatureVerificationInfo> signatureVerificationList =
mSpenSignatureVerificationManager.getInfoList();
try {
if (signatureVerificationList.size() > 0) {
for (SpenSignatureVerificationInfo info : signatureVerificationList) {
if (info.name.equalsIgnoreCase("NRRSignature")) {
mSpenSignatureVerification =
mSpenSignatureVerificationManager
.createSignatureVerification(info);
break;
}
}
} else {
finish();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
Toast.makeText(mContext,
"SpenSignatureVerificationManager class not found.",
Toast.LENGTH_SHORT).show();
return;
} catch (InstantiationException e) {
e.printStackTrace();
Toast.makeText(mContext,
"Failed to access the SpenSignatureVerificationManager constructor.",
Toast.LENGTH_SHORT).show();
return;
} catch (IllegalAccessException e) {
e.printStackTrace();
Toast.makeText(mContext,
"Failed to access the SpenSignatureVerificationManager field or method.",
Toast.LENGTH_SHORT).show();
return;
} catch (SpenCreationFailureException e) {
e.printStackTrace();
Toast.makeText(mContext, "This device does not support Signature
Recognition.",
Toast.LENGTH_SHORT).show();
finish();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(mContext,
"mSpenSignatureVerificationManager engine not loaded.",
Toast.LENGTH_SHORT).show();
return;
}
mSignatureRegistrationNumMax =
mSpenSignatureVerification.getMinimumRequiredCount();
mSignatureList.setOnItemClickListener(new OnItemClickListener() {
@Override
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 224
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
if (position == LIST_REGISRTATION) {
ArrayList<SpenObjectBase> strokeList =
mSpenPageDoc.getObjectList(SpenObjectBase.TYPE_STROKE);
if (strokeList.size() > 0) {
// Add the object on the view to the list.
ArrayList<SpenObjectStroke> list =
new ArrayList<SpenObjectStroke>();
for (int i = 0; i < strokeList.size(); i++) {
list.add((SpenObjectStroke) strokeList.get(i));
}
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 225
mSignatureAdapter.notifyDataSetChanged();
} else if (position == LIST_RETRY) {
// Delete the object for new input.
mSpenPageDoc.removeAllObject();
mSpenSurfaceView.update();
Toast.makeText(mContext, "Draw your signature to register.",
Toast.LENGTH_SHORT).show();
}
}
});
class ListItem {
ListItem(String iTitle, String isubTitle) {
Title = iTitle;
subTitle = isubTitle;
}
String Title;
String subTitle;
}
@Override
public int getCount() {
returnmSignatureListItem.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView,
ViewGroup parent) {
if (convertView == null) {
convertView = Inflater.inflate(
R.layout.signature_list_item, parent, false);
}
if (position == LIST_REGISRTATION) {
TextView title = (TextView) convertView
.findViewById(R.id.signature_list_title);
title.setText(mSignatureListItem.get(position).Title
+ " - ( " + mSignatureRegistrationNum + " / "
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 226
+ mSignatureRegistrationNumMax + " )");
@Override
public void onBackPressed() {
super.onBackPressed();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mSpenSignatureVerification != null) {
mSpenSignatureVerificationManager
.destroySignatureVerification(mSpenSignatureVerification);
mSpenSignatureVerificationManager.close();
}
if(mSpenSurfaceView != null) {
mSpenSurfaceView.close();
mSpenSurfaceView = null;
}
if(mSpenNoteDoc != null) {
try {
mSpenNoteDoc.close();
} catch (Exception e) {
e.printStackTrace();
}
mSpenNoteDoc = null;
}
}
}
public ArrayList<ListItem>mSignatureListItem;
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 227
private SpenPageDoc mSpenPageDoc;
public SpenSurfaceView mSpenSurfaceView;
intmVerificationLevel =
SpenSignatureVerification.VERIFICATION_LEVEL_MEDIUM;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_signature_verification);
mContext = this;
// Initialize Pen.
boolean isSpenFeatureEnabled = false;
Spen spenPackage = new Spen();
try {
spenPackage.initialize(this);
isSpenFeatureEnabled =
spenPackage.isFeatureEnabled(Spen.DEVICE_PEN);
} catch (SsdkUnsupportedException e) {
if( SDKUtils.processUnsupportedException(this, e) == true) {
return;
}
} catch (Exception e1) {
Toast.makeText(mContext, "Cannot initialize Pen.",
Toast.LENGTH_SHORT).show();
e1.printStackTrace();
finish();
}
// Create PenView.
RelativeLayout spenViewLayout =
(RelativeLayout) findViewById(R.id.spenViewLayout);
mSpenSurfaceView = new SpenSurfaceView(mContext);
if (mSpenSurfaceView == null) {
Toast.makeText(mContext, "Cannot create new SpenView.",
Toast.LENGTH_SHORT).show();
finish();
}
spenViewLayout.addView(mSpenSurfaceView);
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 228
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();
}
// After adding a page to NoteDoc, get an instance and set itas a
// member variable.
mSpenPageDoc = mSpenNoteDoc.appendPage();
mSpenPageDoc.setBackgroundColor(0xFFD6E6F5);
mSpenPageDoc.clearHistory();
// Set PageDoc to View.
mSpenSurfaceView.setPageDoc(mSpenPageDoc, true);
if(isSpenFeatureEnabled == false) {
mSpenSurfaceView.setToolTypeAction(SpenSurfaceView.TOOL_FINGER,
SpenSurfaceView.ACTION_STROKE);
Toast.makeText(mContext,
"Device does not support S pen. \n You can draw stroke
with your finger",
Toast.LENGTH_SHORT).show();
}
// Set Verification
mSpenSignatureVerificationManager =
new SpenSignatureVerificationManager(mContext);
List<SpenSignatureVerificationInfo> signatureVerificationList =
mSpenSignatureVerificationManager.getInfoList();
try {
if (signatureVerificationList.size() > 0) {
for (SpenSignatureVerificationInfo info : signatureVerificationList) {
if (info.name.equalsIgnoreCase("NRRSignature")) {
mSpenSignatureVerification = mSpenSignatureVerificationManager
.createSignatureVerification(info);
break;
}
}
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 229
} else {
finish();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
Toast.makeText(mContext,
"SpenSignatureVerificationManager class not found.",
Toast.LENGTH_SHORT).show();
return;
} catch (InstantiationException e) {
e.printStackTrace();
Toast.makeText(mContext,
"Failed to access the SpenSignatureVerificationManager constructor.",
Toast.LENGTH_SHORT).show();
return;
} catch (IllegalAccessException e) {
e.printStackTrace();
Toast.makeText(mContext,
"Failed to access the SpenSignatureVerificationManager field or method.",
Toast.LENGTH_SHORT).show();
return;
} catch (SpenCreationFailureException e) {
e.printStackTrace();
Toast.makeText(mContext, "This device does not support Recognition.",
Toast.LENGTH_SHORT).show();
finish();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(mContext,
"mSpenSignatureVerificationManager engine not loaded.",
Toast.LENGTH_SHORT).show();
return;
}
try {
mSpenSignatureVerification
.setResultListener(new ResultListener() {
@Override
public void onResult(List<SpenObjectStroke> input,
boolean result) {
// Test whether the signature has been successfully
// verified or not.
if (result) {
Toast.makeText(mContext, "Success!",
Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(mContext, "Failure!",
Toast.LENGTH_SHORT).show();
}
mSpenPageDoc.removeAllObject();
mSpenSurfaceView.update();
}
});
} catch (IllegalStateException e) {
e.printStackTrace();
Toast.makeText(mContext, "SpenSignatureVerification is not loaded.",
Toast.LENGTH_SHORT).show();
return;
} catch (Exception e) {
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 230
e.printStackTrace();
Toast.makeText(mContext, "SpenSignatureVerification is not loaded.",
Toast.LENGTH_SHORT).show();
return;
}
mSignatureList.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
if (position == LIST_VERIFICATION) {
ArrayList<SpenObjectBase> strokeList =
SpenPageDoc.getObjectList(SpenObjectBase.TYPE_STROKE);
if (strokeList.size() > 0) {
// Add the object on the view to the list.
ArrayList<SpenObjectStroke> list =
new ArrayList<SpenObjectStroke>();
for (int i = 0; i < strokeList.size(); i++) {
list.add((SpenObjectStroke) strokeList.get(i));
}
mVerificationLevel =
mSpenSignatureVerification.getVerificationLevel();
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 231
})
.setPositiveButton("Confirm",
new DialogInterface.OnClickListener() {
@Override
public void
onClick(DialogInterface dialog,
int whichButton) {
mSpenSignatureVerification
.setVerificationLevel(mVerificationLevel);
mSignatureAdapter
.notifyDataSetChanged();
}
}).setNegativeButton("Cancel", null).show();
} else if (position == LIST_RETRY) {
// Delete the object for new input.
mSpenPageDoc.removeAllObject();
mSpenSurfaceView.update();
Toast.makeText(mContext, "Draw your signature to verify.",
Toast.LENGTH_SHORT).show();
}
}
});
String Title;
String subTitle;
}
@Override
public int getCount() {
returnmSignatureListItem.size();
}
@Override
public Object getItem(int position) {
returnmSignatureListItem.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 232
@Override
public View getView(int position, View convertView,
ViewGroup parent) {
if (convertView == null) {
convertView = Inflater.inflate(
R.layout.signature_list_item, parent, false);
}
if (position == LIST_VERIFICATION) {
TextView title = (TextView) convertView
.findViewById(R.id.signature_list_title);
if (mVerificationLevel
== SpenSignatureVerification.VERIFICATION_LEVEL_LOW) {
title.setText(mSignatureListItem.get(position).Title
+ " ( Level = Low )");
} else if (mVerificationLevel
== SpenSignatureVerification.VERIFICATION_LEVEL_MEDIUM) {
title.setText(mSignatureListItem.get(position).Title
+ " ( Level = Medium )");
} else if (mVerificationLevel
== SpenSignatureVerification.VERIFICATION_LEVEL_HIGH) {
title.setText(mSignatureListItem.get(position).Title
+ " ( Level = High )");
}
@Override
public void onBackPressed() {
super.onBackPressed();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mSpenSignatureVerification != null) {
mSpenSignatureVerificationManager
.destroySignatureVerification(mSpenSignatureVerification);
mSpenSignatureVerificationManager.close();
}
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 233
if(mSpenSurfaceView != null) {
mSpenSurfaceView.close();
mSpenSurfaceView = null;
}
if(mSpenNoteDoc != null) {
try {
mSpenNoteDoc.close();
} catch (Exception e) {
e.printStackTrace();
}
mSpenNoteDoc = null;
}
}
}
IfPenSDK fails to load a plug-in, an exception is thrown with a reason for the error.
mSpenSignatureVerificationManager =
new SpenSignatureVerificationManager(mContext);
List<SpenSignatureVerificationInfo> signatureVerificationList =
mSpenSignatureVerificationManager.getInfoList();
try {
if (signatureVerificationList.size() > 0) {
for (SpenSignatureVerificationInfo info : signatureVerificationList) {
if (info.name.equalsIgnoreCase("NRRSignature")) {
mSpenSignatureVerification = mSpenSignatureVerificationManager
.createSignatureVerification(info);
break;
}
}
} else {
finish();
}
} catch (ClassNotFoundException e) {
} catch (InstantiationException e) {
} catch (IllegalAccessException e) {
} catch (SpenCreationFailureException e) {
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 234
} catch (Exception e) {
}
If the two values are equal, the signatures are normally registered; otherwise, show a message thatno
registered signature exists.
If Verification is selected, check if the minimum specified number of signatures are registered in the
onItemClick() method. Call startActivity()to execute the PenSample5_7_SignatureVerification
activity.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 235
// Move to the Verification menu if any signature is
// registered.
if (registeredCount == minimumRequiredCount) {
Intent intent = new Intent(PenSample5_7_Signature.this,
PenSample5_7_SignatureVerification.class);
startActivity(intent);
} else
Toast.makeText(mContext,
"Registered Signature is less than minimum required count.",
Toast.LENGTH_SHORT).show();
If Delete Signature is selected, check if any signatures are registered in the onItemClick() method. Call
SpenSignatureVerification.unregisterAll()to delete the signature.
1. If Registration is selected and if a stroke object has been added to SpenSurfaceView, call
mSpenPageDoc.getObjectList()in the onItemClick() methodto get the list of objects.
Call mSpenSignatureVerification.register() and pass the list of objects to register the signature.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 236
// Register the object list as a signature.
try {
mSpenSignatureVerification.register(list);
} catch (IllegalStateException e) {
} catch (IllegalArgumentException e) {
} catch (Exception e) {
}
If it is equal to the minimum number of required signatures, call finish()to complete the signature
registration activity and go to the top-levelmenu.
After registering a signature, call SpenPageDoc.removeAllObject() to delete the stroke object for the next
registration.
If Retry is selected, call SpenPageDoc.removeAllObject() to delete the stroke object to allow users to
add new signature strokes.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 237
}
}
Call mSpenSignatureVerification.request() and pass the list of objects to request signature verification.
1. Display a dialog to prompt the user to select a verification level: Low, Medium, or High.
mVerificationLevel =
mSpenSignatureVerification.getVerificationLevel();
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 238
String[] strLevel = { "Low", "Medium", "High" };
1. Based on the value returned by the signature verification plug-in, display the signature verification
results on the viewport. In the sample,Success or Failure.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 239
boolean result) {
// Test whether the signature has been successfully
// verified or not.
if (result) {
Toast.makeText(mContext, "Success!",
Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(mContext, "Failure!",
Toast.LENGTH_SHORT).show();
}
mSpenPageDoc.removeAllObject();
mSpenSurfaceView.update();
}
Call
SpenSignatureVerificationManager.destroySignatureVerification()andSpenSignatureVerifica
tionManager.close()to unload the signature verification plug-in.
if(mSpenSurfaceView != null) {
mSpenSurfaceView.close();
mSpenSurfaceView = null;
}
if(mSpenNoteDoc != null) {
try {
mSpenNoteDoc.close();
} catch (Exception e) {
e.printStackTrace();
}
mSpenNoteDoc = null;
}
}
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 240
The sample application implements the following features:
Replaces the selected stroke object with the SpenObjectStroke recognized as a shape component
when the shape recognition output is calculated.
@Override
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 241
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_shape_recognition);
mContext = this;
// Initialize Spen
boolean isSpenFeatureEnabled = false;
Spen spenPackage = new Spen();
try {
spenPackage.initialize(this);
isSpenFeatureEnabled = spenPackage.isFeatureEnabled(Spen.DEVICE_PEN);
} catch (SsdkUnsupportedException e) {
if (SDKUtils.processUnsupportedException(this, e) == true) {
return;
}
} catch (Exception e1) {
Toast.makeText(mContext, "Cannot initialize Spen.",
Toast.LENGTH_SHORT).show();
e1.printStackTrace();
finish();
}
// Create SpenSurfaceView
mSpenSurfaceView = new SpenSurfaceView(mContext);
if (mSpenSurfaceView == null) {
Toast.makeText(mContext, "Cannot create new SpenSurfaceView.",
Toast.LENGTH_SHORT).show();
finish();
}
mSpenViewLayout.addView(mSpenSurfaceView);
initPenSettingInfo();
// Register the listener
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 242
mSpenSurfaceView.setControlListener(mControlListener);
// Set a button
mSelectionBtn = (ImageView) findViewById(R.id.selectionBtn);
mSelectionBtn.setOnClickListener(mSelectionBtnClickListener);
selectButton(mPenBtn);
setShapeRecognition();
if (isSpenFeatureEnabled == false) {
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();
}
}
List<SpenRecognitionInfo> shapeRecognitionList =
mSpenShapeRecognitionManager.getInfoList(
SpenObjectBase.TYPE_STROKE, SpenObjectBase.TYPE_CONTAINER);
try {
if (shapeRecognitionList.size() > 0) {
for (SpenRecognitionInfo info : shapeRecognitionList) {
if (info.name.equalsIgnoreCase("NRRShape")) {
mShapeRecognition = mSpenShapeRecognitionManager
.createRecognition(info);
break;
}
}
} else {
finish();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
Toast.makeText(mContext, "SpenShapeRecognitionManager class not found.",
Toast.LENGTH_SHORT).show();
return;
} catch (InstantiationException e) {
e.printStackTrace();
Toast.makeText(mContext, "Failed to access the
SpenShapeRecognitionManager constructor.",
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 243
Toast.LENGTH_SHORT).show();
return;
} catch (IllegalAccessException e) {
e.printStackTrace();
Toast.makeText(mContext, "Failed to access the
SpenShapeRecognitionManager field or method.",
Toast.LENGTH_SHORT).show();
return;
} catch (SpenCreationFailureException e) {
// Exit application if the device does not support Recognition feature.
e.printStackTrace();
AlertDialog.Builder ad = new AlertDialog.Builder(this);
ad.setIcon(this.getResources().getDrawable(
android.R.drawable.ic_dialog_alert));
ad.setTitle(this.getResources().getString(R.string.app_name))
.setMessage(
"This device does not support Recognition.")
.setPositiveButton("OK",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
// Close the dialog.
dialog.dismiss();
finish();
}
}).show();
ad = null;
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(mContext, "SpenShapeRecognitionManager engine not
loaded.",
Toast.LENGTH_SHORT).show();
return;
}
try {
mShapeRecognition.setResultListener(new ResultListener() {
@Override
public void onResult(List<SpenObjectBase> input,
List<SpenObjectBase> output) {
// Remove the selected objects and append the recognized objects to pageDoc.
for (SpenObjectBase obj : input) {
mSpenPageDoc.removeObject(obj);
}
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 244
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(mContext, "SpenShapeRecognition is not loaded.",
Toast.LENGTH_SHORT).show();
return;
}
}
@Override
public boolean onCreated(ArrayList<SpenObjectBase> selectedList,
ArrayList<Rect> arg1,
ArrayList<SpenContextMenuItemInfo> arg2,
ArrayList<Integer> arg3, int arg4, PointF arg5) {
if (selectedList.size() > 0 && !mIsProcessingRecognition) {
// List the selected strokes and send the list as a request.
ArrayList<SpenObjectBase> inputList = new
ArrayList<SpenObjectBase>();
for (int i = 0; i < selectedList.size(); i++) {
if (selectedList.get(i).getType() == SpenObjectBase.TYPE_STROKE) {
inputList.add(selectedList.get(i));
}
}
if (inputList.size() <= 0) {
return false;
}
mIsProcessingRecognition = true;
try {
mShapeRecognition.request(inputList);
} catch (IllegalStateException e) {
e.printStackTrace();
Toast.makeText(mContext, "SpenShapeRecognition is not loaded.",
Toast.LENGTH_SHORT).show();
return false;
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(mContext, "SpenShapeRecognition engine not
loaded.",
Toast.LENGTH_SHORT).show();
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 245
return false;
}
return true;
}
return false;
}
@Override
public boolean onClosed(ArrayList<SpenObjectBase> arg0) {
return false;
}
@Override
public boolean onMenuSelected(ArrayList<SpenObjectBase> arg0,
int arg1) {
return false;
}
@Override
public void onObjectChanged(ArrayList<SpenObjectBase> arg0) {
}
@Override
public void onRectChanged(RectF arg0, SpenObjectBase arg1) {
}
@Override
public void onRotationChanged(float arg0, SpenObjectBase arg1) {
}
};
v.setSelected(true);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mShapeRecognition != null) {
mSpenShapeRecognitionManager.destroyRecognition(mShapeRecognition);
mSpenShapeRecognitionManager.close();
}
if (mSpenSurfaceView != null) {
mSpenSurfaceView.closeControl();
mSpenSurfaceView.close();
mSpenSurfaceView = null;
}
if (mSpenNoteDoc != null) {
try {
mSpenNoteDoc.close();
} catch (Exception e) {
e.printStackTrace();
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 246
}
mSpenNoteDoc = null;
}
}
}
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 247
private SpenNoteDoc mSpenNoteDoc;
private SpenPageDoc mSpenPageDoc;
private SpenSurfaceView mSpenSurfaceView;
RelativeLayout mSpenViewLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_stroke_frame);
mContext = this;
// Initialize Pen.
boolean isSpenFeatureEnabled = false;
Spen spenPackage = new Spen();
try {
spenPackage.initialize(this);
isSpenFeatureEnabled = spenPackage.isFeatureEnabled(Spen.DEVICE_PEN);
} catch (SsdkUnsupportedException e) {
if( SDKUtils.processUnsupportedException(this, e) == true) {
return;
}
} catch (Exception e1) {
Toast.makeText(mContext, "Cannot initialize Pen.",
Toast.LENGTH_SHORT).show();
e1.printStackTrace();
finish();
}
mSpenViewLayout =
(RelativeLayout) findViewById(R.id.spenViewLayout);
// Create PenView.
mSpenSurfaceView = new SpenSurfaceView(mContext);
if (mSpenSurfaceView == null) {
Toast.makeText(mContext, "Cannot create new SpenSurfaceView.",
Toast.LENGTH_SHORT).show();
finish();
}
mSpenViewLayout.addView(mSpenSurfaceView);
// setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 248
finish();
} catch (Exception e) {
e.printStackTrace();
finish();
}
// After adding a page to the NoteDoc, get an instance and set it as a member variable.
mSpenPageDoc = mSpenNoteDoc.appendPage();
mSpenPageDoc.setBackgroundColor(0xFFD6E6F5);
mSpenPageDoc.clearHistory();
// Set a PageDoc to View.
mSpenSurfaceView.setPageDoc(mSpenPageDoc, true);
initPenSettingInfo();
// Register listener.
mSpenSurfaceView.setControlListener(mControlListener);
// Define buttons.
mStrokeFrameBtn = (ImageView) findViewById(R.id.videoBtn);
mStrokeFrameBtn.setOnClickListener(mFrameBtnClickListener);
if(isSpenFeatureEnabled == false) {
mSpenSurfaceView.setToolTypeAction(SpenSurfaceView.TOOL_FINGER,
SpenSurfaceView.ACTION_STROKE);
Toast.makeText(mContext,
"Device does not support S pen. \n You can draw stroke with yourfinger",
Toast.LENGTH_SHORT).show();
}
}
mSpenSurfaceView.cancelStrokeFrame();
} else {
// Create a frame with the objects and start taking a picture.
ArrayList<SpenObjectBase> oList =
mSpenPageDoc.getObjectList(SpenPageDoc.FIND_TYPE_STROKE);
if (oList.size() != 0) {
mStrokeFrameBtn.setImageResource(R.drawable.tool_ic_stop);
mStrokeFrameStarted = true;
ArrayList<SpenObjectStroke> osList =
new ArrayList<SpenObjectStroke>();
for (SpenObjectBase o : oList) {
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 249
osList.add((SpenObjectStroke) o);
}
mSpenSurfaceView.update();
mStrokeFrameBtn.setEnabled(false);
mSpenSurfaceView.takeStrokeFrame((Activity) mContext,
mSpenViewLayout, osList, mStrokeFrameListener);
mSpenSurfaceView.closeControl();
mStrokeFrameBtn.setEnabled(true);
} else {
Toast.makeText(mContext,
"It doesn't work.\nPlease draw the stroke.",
Toast.LENGTH_SHORT).show();
}
}
}
};
@Override
public booleanonClosed(ArrayList<SpenObjectBase> objectList) {
return false;
}
@Override
public booleanonCreated(ArrayList<SpenObjectBase> objectList,
ArrayList<Rect> relativeRectList,
ArrayList<SpenContextMenuItemInfo> menu,
ArrayList<Integer> styleList, int pressType, PointF point ) {
if (objectList == null) {
return false;
}
SpenControlBase control = mSpenSurfaceView.getControl();
if(control != null) {
control.setContextMenuVisible(true);
}
// Set a context menu.
menu.add(new SpenContextMenuItemInfo(CONTEXT_MENU_DELETE,
"Delete", true));
// Add Retake context menu item if the selected object is a container.
if(objectList.get(0).getType() == SpenObjectBase.TYPE_CONTAINER) {
menu.add(new SpenContextMenuItemInfo(CONTEXT_MENU_RETAKE,
"Re Take", true));
mStrokeFrameContainer = (SpenObjectContainer) objectList.get(0);
}
return true;
}
@Override
public booleanonMenuSelected(
ArrayList<SpenObjectBase> objectList, int itemId) {
if (objectList == null) {
return true;
}
// Delete the selected object (Stroke Frame).
if (itemId == CONTEXT_MENU_DELETE) {
mSpenPageDoc.removeSelectedObject();
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 250
mSpenSurfaceView.closeControl();
mSpenSurfaceView.update();
// Retake StrokeFrame.
} else if(itemId == CONTEXT_MENU_RETAKE) {
SpenControlBase control = mSpenSurfaceView.getControl();
if(control != null) {
control.setContextMenuVisible(false);
}
mSpenSurfaceView.retakeStrokeFrame((Activity)mContext,mSpenViewLayout,
mStrokeFrameContainer, mStrokeFrameListener);
mStrokeFrameBtn.setImageResource(R.drawable.tool_ic_stop);
mStrokeFrameStarted = true;
}
return false;
}
@Override
public void onObjectChanged(ArrayList<SpenObjectBase> object) {
}
@Override
public void onRectChanged(RectF rect, SpenObjectBase object) {
}
@Override
public void onRotationChanged(float angle,
SpenObjectBase objectBase) {
}
};
@Override
public void onCanceled(int state, SpenObjectContainer o) {
}
};
@Override
protected void onDestroy() {
super.onDestroy();
if(mSpenSurfaceView != null) {
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 251
mSpenSurfaceView.close();
mSpenSurfaceView = null;
}
if(mSpenNoteDoc != null) {
try {
mSpenNoteDoc.close();
} catch (Exception e) {
e.printStackTrace();
}
mSpenNoteDoc = null;
}
}
}
In theonClick() method, if a picture is being taken, cancel the Stroke Frame by calling
SpenSurfaceView.cancelStrokeFrame(). Otherwise, call SpenSurfaceView.takeStrokeFrame() to
start taking a picture and pass the stroke drawn on the viewport and your SpenStrokeFrameListener
instance as input parameters.
mSpenSurfaceView.cancelStrokeFrame();
} else {
// Create Stroke Frame with the objects and start taking a picture.
ArrayList<SpenObjectBase> oList =
mSpenPageDoc.getObjectList(SpenPageDoc.FIND_TYPE_STROKE);
if (oList.size() != 0) {
mStrokeFrameBtn.setImageResource(R.drawable.tool_ic_stop);
mStrokeFrameStarted = true;
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 252
ArrayList<SpenObjectStroke> osList =
new ArrayList<SpenObjectStroke>();
for (SpenObjectBase o : oList) {
osList.add((SpenObjectStroke) o);
}
mSpenSurfaceView.update();
mSpenSurfaceView.takeStrokeFrame((Activity) mContext,
mSpenViewLayout, osList, mStrokeFrameListener);
} else {
Toast.makeText(mContext,
"It doesn't work.\nPlease draw the stroke.",
Toast.LENGTH_SHORT).show();
}
}
}
};
1. Create an SpenControlListener instance for control events on the viewport and register it by calling
SpenSurfaceView.setControlListener().
.........
@Override
public booleanonCreated(ArrayList<SpenObjectBase> objectList,
ArrayList<Rect> relativeRectList,
ArrayList<SpenContextMenuItemInfo> menu,
ArrayList<Integer> styleList, int pressType, PointF point ) {
if (objectList == null) {
return false;
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 253
}
SpenControlBase control = mSpenSurfaceView.getControl();
if(control != null) {
control.setContextMenuVisible(true);
}
// AddDelete context menu item.
menu.add(new SpenContextMenuItemInfo(CONTEXT_MENU_DELETE,
"Delete", true));
// Add Retakecontext menu item if the selected object is acontainer.
if(objectList.get(0).getType() == SpenObjectBase.TYPE_CONTAINER) {
menu.add(new SpenContextMenuItemInfo(CONTEXT_MENU_RETAKE,
"Re Take", true));
mStrokeFrameContainer = (SpenObjectContainer) objectList.get(0);
}
return true;
}
@Override
public boolean onMenuSelected(
ArrayList<SpenObjectBase> objectList, int itemId) {
if (objectList == null) {
return true;
}
// Delete the selected object (Stroke Frame).
if (itemId == CONTEXT_MENU_DELETE) {
mSpenPageDoc.removeSelectedObject();
mSpenSurfaceView.closeControl();
mSpenSurfaceView.update();
// Retake StrokeFrame.
} else if(itemId == CONTEXT_MENU_RETAKE) {
SpenControlBase control = mSpenSurfaceView.getControl();
if(control != null) {
control.setContextMenuVisible(false);
}
mSpenSurfaceView.retakeStrokeFrame((Activity)mContext,
mSpenViewLayout,
mStrokeFrameContainer, mStrokeFrameListener);
mStrokeFrameBtn.setImageResource(R.drawable.tool_ic_stop);
mStrokeFrameStarted = true;
}
return false;
}
.........
};
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 254
In the onCompleted() method, which is called when taking a picture is completed:
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 255
Copyright
Though every care has been taken to ensure the accuracy of this document, Samsung Electronics Co.,
Ltd.cannot accept responsibility for any errors or omissions or for any loss occurred to any person,whether
legal or natural, from acting, or refraining from action, as a result of the information contained herein.
Information in this document is subject to change at any time without obligation to notify any person of
such changes.
Samsung Electronics Co. Ltd.may have patents or patent pending applications, trademarks copyrights or
other intellectual property rights covering subject matter in this document.The furnishing of this document
does not give the recipient or reader any license to these patents, trademarks copyrights or other
intellectual property rights.
No part of this document may be communicated, distributed, reproduced or transmitted in any form or by
any means, electronic or mechanical or otherwise, for any purpose, without the prior written permission of
Samsung Electronics Co. Ltd.
All brand names and product names mentioned in this document are trademarks or registered trademarks
of their respective owners.
Copyright Samsung Electronics Co., Ltd. All rights reserved. Page 256