יום חמישי, 24 במאי 2012

Personal Firewall





הרבה זמן רציתי לכתוב את המאמר הזה ועכשיו הגיע הזמן לסגור עניין למען האמת מדובר על 2 מאמרים בהם אני יסביר כיצד  לממש Personal Firewall בסביבת Windows, לא מדובר על התממשקות לתוכנת ה Firewall הקיימת במערכת ההפעלה, אלא נגיעה בשכבה נמוכה יותר שבעצם נותנת שירותים של Packet Filtering כחלק מה Api של המערכת עצמה.

למה לא יכלת לסגור את כל הסיפור במאמר אחד?
הלוואי, בגרסת Windows Vista ומעלה החליטו לשנות את צורת ההתממשקות, בעצם הקימו פלטפורמה חדשה ומאובזרת שנקראת Windows Filtering Platform ועליה נעבור במאמר הבא בנושא.

נחזור לעניינו, רוב העבודה מתבצעת מול הקובץ iphlpapi.dll  שהוא חיוני עבור מערכת ההפעלה, הוא בעצם חלק מה Api של מערכת ההפעלה ואחראי על המנגנון Ip Helper Api Libary שמאפשר לנו גישה למשאבי הרשת.

שימו לב: התוכנה תומכת רק בגרסאות Windows Server 2003 ו XP, התוכנית חייבת הרשאות גבוהות (Administrator) בשביל לרוץ.

פונקציות ה Api עבור הגדרת Filter:

Interface:
PfCreateInterface(...);
יצירת  Interface ואיתחול.
PfBindInterfaceToIPAddress(...);
חיבור ה interface לכתובת Ip.
PfUnBindInterface(...);
ניתוק כתובת מ Interface.
PfDeleteInterface(...);
הסרת ה Interface.


Filters:
PfAddFiltersToInterface(...);
הוספת Filter חדש ל Interface.
PfRemoveFiltersFromInterface(...);
הסרת ה Filter.


Global Filters:

קבוצה של פילטרים גלובלים עבור ה interface וכל פילטר רגיל התחשב בו, מדובר על 3 דגלים שניתן להרים בסינון:

GF_FRAGMENTS
בדיקת תקינות עובר החבילות.
GF_STRONGHOST
בדיקת תקינות של היעד שממנו הגיעו החבילות.
GF_FRAGCACHE
בדיקת החבילה שנמצאות ב Cache.

בעצם ניתן להוסיף שכבת הגנה נוספת שמאפשרת לזהות הזרקות של חבילות ו Ip Spoofing.

PfAddGlobalFilterToInterface(...);
הוספת Global Filter חדש.
PfRemoveGlobalFilterFromInterface(...);
הסרת ה Global Filter.

על מנת להשתמש בממשק, התוכנית חייבת להיות כתובה ב C / C++ , קיימים 2 סוגים שונים של ניהול זיכרון, Managed Code זיכרון שמוקצה רק תחת ה (Common Language Runtime virtual machine כלומר ה CLR של .Net) ו Unmanaged Code שנמצא מחוץ לסביבה הוירטואלית, פונקציות Api של Windows עובדות עם זיכרון מסוג זה בלבד ולכן חייבים לעשות את החיבור עם המנגנון המובנה ב Compiler של C++ שנקרא C++ Interop שמחבר עם 2 סוגי הזיכרון ומאפשר להפעיל את ה DLL דרך הקוד של .Net.



בגלל שאי אפשר לגשת לפונקציות של ה API ישירות דרך .NET יש לבנות קבוצה של פונקציות שמקבלות את הפרמטרים  של הפילטר מעולם ה Managed Code ומעבירות אותו ל UnManaged Code שמדבר עם ה API, התוכנית עצמה מורכבת מ 3 מחלקות עיקריות:

ndfInterface
יוצר Interface חדש עבור ה Filter עבור ה Adapters.
ndfFilterFlag
פרמטרים קבועים המאפשרים לקבוע את כיון ה Traffic, סוג הפרוטוקולים, פרמטרים עבור GlobalFilter, שאותם נעביר עם הפילטר שנשלח.
ndfFilterManager
החיבור שלנו לעולם ה Managed Code.

הפרמטרים שעוברים בפונקציות נכנסים לאובייקט מסוג PF_FILTER_DESCRIPTOR שמנוהל ב  UnManaged Code והוא עובר ל Api.

ndf.h

// **** proxytype.blogspot.com ****
// Network Filter Interface
// free for anyuse.
// please do not remove this note
// ********************************


#include <windows.h>
#include <Iphlpapi.h>
#include <Fltdefs.h>

#pragma comment(lib, "Iphlpapi.lib")

#pragma once
#using <mscorlib.dll>
#using <System.dll>
using namespace System;
using namespace System::Net;
using namespace System::Collections;
using System::Runtime::InteropServices::Marshal;


namespace ndf
{
private __gc class ndfInterface
{
public:
INTERFACE_HANDLE * myhandle;

   ndfInterface();
int createInterface(IPAddress *ip);

protected:
void dispose();
};


public __gc class ndfFilterFlag
{
public:
//direction of traffic
static const int DIRECTION_IN = 0x0;
static const int DIRECTION_OUT = 0x1;

//set for all types
static const int ANY_TCPUDP_PORTS = 0x00;
static const int ANY_ICMP_TYPES = 0xff;
static const int ANY_ICMP_CODES = 0xff;
     
//set for all supported protocol
static const int PROTOCOL_ANY = 0x00;
static const int PROTOCOL_TCP = 0x06;
static const int PROTOCOL_UDP = 0x17;
static const int PROTOCOL_ICMP = 0x01;

//set for all global filter type
static const int GF_FRAGMENTS  = 2;
static const int GF_STRONGHOST = 8;
static const int GF_FRAGCACHE  = 9;

};

public __gc class ndfFilterManager
{
protected:
bool disposed;
public:

Hashtable * interfaces;
   
        ndfFilterManager();
                 int signFilter(IPAddress *ip, int direction, IPAddress *srcIp, IPAddress *srcMask,
                 IPAddress *dstIp, IPAddress * dstMask, int srcPort, int dstPort, int protocol);

                int signGlobalFilter(IPAddress *ip,int gbFilter);

int removeFilter(IPAddress *ip, int direction, IPAddress *srcIp, IPAddress *srcMask, IPAddress *dstIp, IPAddress * dstMask, int srcPort, int dstPort, int protocol);
int removeGlobalFilter(IPAddress *ip,int gbFilter);

void dispose();
};
}


ndf.cpp

// **** proxytype.blogspot.com ****
// Network Filter Interface
// free for anyuse.
// please do not remove this note
// ********************************


#include "stdafx.h"
#include "ndf.h"



int ndf::ndfInterface::createInterface(IPAddress *ip)
{
   
  myhandle = (INTERFACE_HANDLE *)Marshal::AllocHGlobal(sizeof(INTERFACE_HANDLE)).ToPointer();
   
  //set default rules before adding new rules
  DWORD code = PfCreateInterface(0, 
    PF_ACTION_FORWARD, 
    PF_ACTION_FORWARD, 
FALSE, 
TRUE, 
    myhandle);
  //check if creation success
  if(code != NO_ERROR)
return -1;

  unsigned long longIp = (unsigned long)ip->get_Address();

  code = PfBindInterfaceToIPAddress(*myhandle,PF_IPV4,(PBYTE)&longIp);

  //check if binding success
  if(code != NO_ERROR)
  {
 //delete the interface if binding unsuccess
 PfDeleteInterface(*myhandle);
 return -2;
  }
  
  return 0;


}


ndf::ndfInterface::ndfInterface()
{
   myhandle = NULL;
}

void ndf::ndfInterface::dispose()
{
   //clear the handler and associate memory
   if(myhandle != NULL)
 Marshal::FreeHGlobal(myhandle);


}

ndf::ndfFilterManager::ndfFilterManager()
{
interfaces = new Hashtable();

//set disposed status to false
//when change to true
//dispose complete
disposed = false;

}

int ndf::ndfFilterManager::signFilter(IPAddress *ip, int direction, IPAddress *srcIp, IPAddress *srcMask, IPAddress *dstIp, IPAddress * dstMask, int srcPort, int dstPort, int protocol)
{
ndfInterface * handleNum;

// check if ip belong to
// interface inside the
// hash collection 
if(interfaces->Contains(ip))
{
//return object by ip
//and casting the object
//to ndfInterface.
handleNum = static_cast<ndfInterface *>(interfaces->get_Item(ip));
}
else
{
//if no interface found 
//create new one and insert
//to the hash collection
handleNum = new ndfInterface();
if(handleNum->createInterface(ip)!= 0)
return -1;

interfaces->Add(ip, handleNum);
}



//create operation system native filter
//structure, complete the needed fields
PF_FILTER_DESCRIPTOR systemFilter;
systemFilter.dwFilterFlags     = FD_FLAGS_NOSYN;
   systemFilter.dwRule            = 0;
systemFilter.pfatType          = PF_IPV4;
systemFilter.dwProtocol        = protocol;
systemFilter.fLateBound        = 0;
systemFilter.wSrcPort          = srcPort;
systemFilter.wSrcPortHighRange = srcPort;
systemFilter.wDstPort          = dstPort;
systemFilter.wDstPortHighRange = dstPort;

unsigned long srcIpNum    = (unsigned long)srcIp->get_Address();
unsigned long dstIpNum = (unsigned long)dstIp->get_Address();
unsigned long srcMaskNum = (unsigned long)srcMask->get_Address();
unsigned long dstMaskNum = (unsigned long)dstMask->get_Address();

//casting to 8-bit unsigned entity pointer
systemFilter.SrcAddr = (PBYTE) &srcIpNum;
systemFilter.SrcMask = (PBYTE) &srcMaskNum;
systemFilter.DstAddr = (PBYTE) &dstIpNum;
systemFilter.DstMask = (PBYTE) &dstMaskNum;

DWORD code;


//payloads are different between directions
switch (direction)
{
case 0:
code = PfAddFiltersToInterface(*(handleNum->myhandle), 1, &systemFilter, 0, NULL, NULL );
break;
case 1:
code = PfAddFiltersToInterface(*(handleNum->myhandle), 0, NULL, 1, &systemFilter, NULL );
break;
default:
code = ERROR;
}

if(code != NO_ERROR)
return -1;

return 0;
}

int ndf::ndfFilterManager::signGlobalFilter(IPAddress *ip,int gbFilter)
{
ndfInterface * handleNum;

// check if ip belong to
// interface inside the
// hash collection 
if(interfaces->Contains(ip))
{
//return object by ip
//and casting the object
//to ndfInterface.
handleNum = static_cast<ndfInterface *>(interfaces->get_Item(ip));
}
else
{
//if no interface found 
//create new one and insert
//to the hash collection
handleNum = new ndfInterface();
if(handleNum->createInterface(ip)!= 0)
return -1;

interfaces->Add(ip, handleNum);
}


DWORD code;

// add the global filter to
// interface convert the int for
// global_filter system type
code = PfAddGlobalFilterToInterface(*(handleNum->myhandle), (GLOBAL_FILTER)gbFilter);
if(code != NO_ERROR)
return -1;

return 0;
}

int ndf::ndfFilterManager::removeFilter(IPAddress *ip, int direction, IPAddress *srcIp, IPAddress *srcMask, IPAddress *dstIp, IPAddress * dstMask, int srcPort, int dstPort, int protocol)
{
ndfInterface * handleNum;

// check if ip belong to
// interface inside the
// hash collection 
if(interfaces->Contains(ip))
//return object by ip
//and casting the the object
//to ndfInterface.
handleNum = static_cast<ndfInterface *>(interfaces->get_Item(ip));
else
//if not information found
//return error
return -1;


//create operation system native filter
//structure and complete the nedded fields
PF_FILTER_DESCRIPTOR systemFilter;
systemFilter.dwFilterFlags     = FD_FLAGS_NOSYN;
   systemFilter.dwRule            = 0;
systemFilter.pfatType          = PF_IPV4;
systemFilter.dwProtocol        = protocol;
systemFilter.fLateBound        = 0;
systemFilter.wSrcPort          = srcPort;
systemFilter.wSrcPortHighRange = srcPort;
systemFilter.wDstPort          = dstPort;
systemFilter.wDstPortHighRange = dstPort;

unsigned long srcIpNum    = (unsigned long)srcIp->get_Address();
unsigned long dstIpNum = (unsigned long)dstIp->get_Address();
unsigned long srcMaskNum = (unsigned long)srcMask->get_Address();
unsigned long dstMaskNum = (unsigned long)dstMask->get_Address();

//casting to 8-bit unsigned entity pointer
systemFilter.SrcAddr = (PBYTE) &srcIpNum;
systemFilter.SrcMask = (PBYTE) &srcMaskNum;
systemFilter.DstAddr = (PBYTE) &dstIpNum;
systemFilter.DstMask = (PBYTE) &dstMaskNum;

DWORD code;

//payloads are different between directions
switch (direction)
{
case 0:
  code = PfRemoveFiltersFromInterface(*(handleNum->myhandle), 1, &systemFilter, 0, NULL);
break;
case 1:
  code = PfRemoveFiltersFromInterface(*(handleNum->myhandle), 0, NULL, 1, &systemFilter);
  break;
default:
code = ERROR;
}

if(code != NO_ERROR)
return -1;

return 0;


}

int ndf::ndfFilterManager::removeGlobalFilter(IPAddress *ip,int gbFilter)
{
       ndfInterface *handleNum;

// check if ip belong to
// interface inside the
// hash collection
if(interfaces->Contains(ip))
//return object by ip
//and casting the object
//to ndfInterface.
handleNum = static_cast<ndfInterface *>(interfaces->get_Item(ip));
else
{
//if not exsits create an new
//object inside the collection 
       // and attach the request ip
handleNum = new ndfInterface();

//check if the creation of the
//handle acomplish if there is
//error throw -1
if(handleNum->createInterface(ip)!= 0)
return -1;
interfaces->Add(ip, handleNum);
}

DWORD code;
// remove the global filter from
// interface convert the int for
// global_filter system type
code = PfRemoveGlobalFilterFromInterface(*(handleNum->myhandle), (GLOBAL_FILTER)gbFilter);
if(code != NO_ERROR)
return -1;
            
return 0;
}

void ndf::ndfFilterManager::dispose()
{
if(!disposed)
{
disposed = true;
ndfInterface *handleNum;
IDictionaryEnumerator* Enumerator = interfaces->GetEnumerator();

//run through the collection
//and unbind and remove the interface
while ( Enumerator->MoveNext() )
{
handleNum = static_cast<ndfInterface *>(Enumerator->Value);
PfUnBindInterface(*(handleNum->myhandle));
PfDeleteInterface(*(handleNum->myhandle));
}
//active the garbage collector
GC::SuppressFinalize(this);
}
}


test.cs

using System;
using System.Net;
using ndf;

namespace test
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
            ndfFilterManager mymanager = new ndfFilterManager();
            mymanager.signFilter(IPAddress.Parse("192.168.1.12"),
                ndfFilterFlag.DIRECTION_OUT,
                IPAddress.Parse("192.168.1.12"),
                IPAddress.Parse("255.255.255.255"),
                IPAddress.Parse("212.199.164.135"),
                IPAddress.Parse("255.255.255.255"),
                ndfFilterFlag.ANY_TCPUDP_PORTS,
                80,
                ndfFilterFlag.PROTOCOL_TCP);
       
          Console.ReadLine();
                   mymanager.dispose();
}
}
}




:סרט הדגמה


קוד להורדה:

סיכום:
ראינו כיצד לממש Personal FireWall בעזרת פונקציות API של מערכת ההפעלה.
נתראה בחלק הבא.

יום רביעי, 16 במאי 2012

Arduino Laser Pointer Guide



אז אחרי הפסקה קצרה נחזור ל Arduino ונעבוד עם משהו חדש, הפעם מדובר על סמן לייזר , כן הדבר הזה שיורה נקודה אדומה למרחקים , שמסנוור , מעצבן וכל אמא אומרת "אל תכוון לעיניים", ניתן למצוא אותם בפשטות ברחבי האינטרנט, את שלי הזמנתי דרך DX שעלה לי רק דולר אחד בודד (אני חושב...).

דרישות:
  • Arduino Uno
  • Arduino Prototype Shield
  • Laser Pointer
  • Wires



Laser Pointer:

החיבור עצמו מאוד פשוט וסה"כ מדובר ב 2 חוטים ,הראשון נכנס ל Pin שב Arduino והשני נכנס ל GND , קיימים המון סוגים של Laser Pointer, וניתן למצוא אותם בצבעים ובסמנים שונים ,העוצמה היא החלק המסוכן ביותר ועלולה לגרום לעיוורון וכוויות (כבר אמרו פה "לא לכוון לעיניים"?).


מבנה סופי:


שלא תתבלבלו חלק מהחוטים נועדו להחזיק את החוטים של ה Laser Pointer במקום.

קוד:

//set the laser pin
int laserpin =2;

 void setup()
 {
   //set the pin mode as OUTPUT
   pinMode(laserpin,OUTPUT);

 }

 void loop()
 {
  digitalWrite(laserpin,HIGH);
  delay(500);
  digitalWrite(laserpin,LOW);
  delay(500);
 }

סיכום:
ניתן לממש עם סמני לייזר המון דברים בתחומים שונים כמו האבטחה, תאורה וכו' , אין ספק שסמני לייזר מעצבנים אבל עכשיו הם מעצבנים אוטומטית עם ה Arduino.

לא לכוון לעיניים!


יום שבת, 12 במאי 2012

Android Camera Guide



האמת היא שאת המאמר הזה אני כותב בצל עסקת הענק של Instagram שנמכרה ל Facebook בסכום דמיוני של מיליארד דולר וחשבתי לעצמי נושא הצילום נהפך לכלי רציני בפלאפונים במיוחד בעידן ה SmartPhone שהכל נהפך לאפשרי, אם חשבתם שפלאפון הוא רק לדיבורים אז אתם חיים בסרט ואני לא יוסיף יותר, בסדרת המאמרים הקרובה נתעסק עם החומרה של הפלאפונים שלנו אז בראשית נתחיל עם המצלמה כי היא בהחלט נהפכה למשהו מאוד איכותי בשנים האחרונות ומאפשרת לנו להפיק תמונות באיכות גבוהה.

קצת תאוריה:

ב Framework של Android נוכל למצוא מחלקות מגוונות עבור רכיבי החומרה, לשימוש במצלמה ב Android יש להשתמש במחלקות המוגדרות כ Multimedia, דרכן תתבצע התקשורת עם החומרה.
שימו לב! המצלמה יכולה להיות משוייכת לתוכנית אחת בלבד לכן חשוב לשחרר את משאבי המערכת של המצלמה על מנת שתוכניות אחרות יוכלו להשתמש בה.

SurfaceView

להצגת הפלט של המצלמה יש לעבוד עם מחלקת Surface שזה בעצם סוג של Buffer ,  הבעיה שלא משנה איפה נמקם אותו הוא יעלם על ידי החלון של התוכנית שלנו כי הוא מוגדר ב Z index הנמוך ביותר בההרכיה של ה Gui  ב Android לכן יש להשתמש ב SurfaceView שמכיל בתוכו Surface והיתרון הגדול שהוא בעצם עושה "חור" בחלון התוכנית ומאפשר לנו לראות את הפלט המצלמה.

יש לממש מספר פונקציות של ה SurfaceView:

//creating the surface, and connecting the camera display buffer
public void surfaceCreated(SurfaceHolder holder) {}

//destroy the surface in this point you must to release all camera resources
public void surfaceDestroyed(SurfaceHolder holder) {}

//occur when the surface size change 
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {}


Camera

המצלמה היא אובייקט סטטי ולא ניתן לייצר ממנו Instance , תחילה ננסה לבקש את המצלמה ממערכת ההפעלה וננסה לחבר אותה ל Surface כאשר הפונקציה SurfaceCreated מתממשת ב SurfaceView.

public void surfaceCreated(SurfaceHolder holder) {

               try {

                //set the camera to open in this point our application
//taking control of the camera and blocking others applications
  camera = Camera.open();
//set the camera display to the holder
camera.setPreviewDisplay(holder);
                        //start preview the camera output
camera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}


מימוש SurfaceDestroyed היא קריטית וכבר הסברתי למה, חייבים לשחרר את המצלמה

//happen when we destroyed the surface
public void surfaceDestroyed(SurfaceHolder holder) {
if (camera!=null){
              camera.stopPreview();
              //free the resources
              camera.release();
}
}


כאשר משתנה ה SurfaceView מתבצעת הפונקציה של SurfaceChanged , לדוגמה כשהמסך מסתובב.

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
  //when the surface size changed, first happen SurfaceDestroyed
//so we need to reconnect to the camera to the surface
//getting the parameters from the camera and 
//change the width and the height of the camera
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(w, h);
camera.setParameters(parameters);
try {
 camera.setPreviewDisplay(mHolder);
 camera.startPreview();
} catch (IOException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
}
}

נארוז את הכל ב Class אחד שמוגדר כ Preview  שמציג לנו את המצלמה, בעצם יצרנו שכבה שמשלבת גם את המצלמה וגם את ה Surface.

import java.io.IOException;
import android.content.Context;
import android.content.res.Configuration;
import android.hardware.Camera;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

class Preview extends SurfaceView implements SurfaceHolder.Callback {

//interface to the display surface 
SurfaceHolder mHolder;
//static instance for the camera
public Camera camera;


Preview(Context context) {
super(context);

// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
 
//creation the surface 
//and connecting to the camera
public void surfaceCreated(SurfaceHolder holder) {

   //set the camera to open
//in this point our application
//taking control of the camera and 
//blocking others
  camera = Camera.open();

 //set the camera rotation to portrait
   camera.setDisplayOrientation(90);

try {

//set the camera display to the holder
camera.setPreviewDisplay(holder);
camera.startPreview();


} catch (IOException e) {
e.printStackTrace();
}
}

//happen when we destroyed the surface
public void surfaceDestroyed(SurfaceHolder holder) {
 if (camera!=null){
              camera.stopPreview();
              //free the resources
              camera.release();
  }
}

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
 //when the surface size changed, first happen SurfaceDestroyed
//so we need to reconnect to the camera to the surface
//getting the parameters from the camera and 
//change the width and the height of the camera

Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(w, h);
camera.setParameters(parameters);
try {
camera.setPreviewDisplay(mHolder);
camera.startPreview();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}
}



Activity

הפרויקט מחולק ל 2 חלקים הראשון הוא בעצם ה Activity שלנו (האפליקציה עצמה) והחלק השני הוא ה Preview שאותו נחבר לאפליקציה, קיים חלק נוסף שמתממש ב Activity והוא שמירת התמונה כקבוץ ע"ג המכשיר שלנו.

העבודה מתבצעת עם 3 פונקציות callback שחוזרות לנו מהמצלמה שנמצאת ב Preview שלנו, הראשונה נקראת shutterCallback שמתבצעת ברגע לקיחת תמונה מהמצלמה, השניה rawCallback כאשר מתמלא Buffer של התמונה, והשלישית jpegCallback כאשר מתמלא Buffer של התמונה לאחר Compress.



 public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
setContentView(R.layout.main);

//create new instance to the surface
preview = new Preview(this);

//set the surface to the xml in the surface
((FrameLayout) findViewById(R.id.preview)).addView(preview);

//set button listener.
buttonClick = (Button) findViewById(R.id.buttonClick);
buttonClick.setOnClickListener(new OnClickListener() {
public void onClick(View v) {

//set the camera inside the surface to
//take a picture, the function have 3
//calls back  to the activity
//* shutterCallback the actual event 
//of the capturing happen
//* RawCallBack where the buffer was fill
//by the camera image
//* jpegCallback happen where compress 
//image created
preview.camera.takePicture(shutterCallback, rawCallback,
jpegCallback);
}
});

Log.d(TAG, "Created");
    }

//happen when picture was taken
ShutterCallback shutterCallback = new ShutterCallback() {
   public void onShutter() {
Log.d(TAG, "Shutter");
   }
};

//happen when the image fill buffer
PictureCallback rawCallback = new PictureCallback() {
    public void onPictureTaken(byte[] data, Camera camera) {
Log.d(TAG, "onPictureTaken - raw");
    }
};



בקיצור הפונקציה שעושה את רוב העבודה היא jpegCallback ששומרת לנו את הקובץ ע"ג המכשיר.

//happen when the jepg buffer fill.
PictureCallback jpegCallback = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
  try {
           
                             //crate the metadata of the image
           ContentValues image = new ContentValues();
           
           // add metadata tags:
           image.put(Media.DISPLAY_NAME, "proxytype.blog image");
           image.put(Media.MIME_TYPE, "image/jpg");
           image.put(Media.TITLE, "this is camera test");
           image.put(Media.DESCRIPTION, "enjoy the photo");

           // write the rotation information of the image
           switch (mOrientation) {
               case ORIENTATION_PORTRAIT_NORMAL:
                   image.put(Media.ORIENTATION, 90);
                   break;
               case ORIENTATION_LANDSCAPE_NORMAL:
                   image.put(Media.ORIENTATION, 0);
                   break;
               case ORIENTATION_PORTRAIT_INVERTED:
                   image.put(Media.ORIENTATION, 270);
                   break;
               case ORIENTATION_LANDSCAPE_INVERTED:
                   image.put(Media.ORIENTATION, 180);
                   break;
           }
           
           //set the image location
           Uri uriTarget = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, image);
           
           //set the stream for the image
           OutputStream imageFileOS;
           
           try {
           
           
            imageFileOS = getContentResolver().openOutputStream(uriTarget);
            //write the data buffer of the image
            //to the file
            imageFileOS.write(data);
             
            //close the stream
            imageFileOS.flush();
            imageFileOS.close();
             
            Toast.makeText(CameraTestActivity.this,
                "Image saved: " + uriTarget.toString(),
                Toast.LENGTH_LONG).show();
             
           } catch (Exception e) {
               e.printStackTrace();
           }
       } catch (Exception e) {
           e.printStackTrace();
       }
   }
};

חשוב מאוד! לבקש הרשאות למצלמה ב Mainfest ממולץ לנטרל את ה Rotation של התוכנית על מנת שה SurfaceView לא ישתנה.
<uses-permission android:name="android.permission.CAMERA" />

<activity
            android:label="@string/app_name"
            android:name=".CameraTestActivity"
            android:screenOrientation="portrait">




הורדת הפרויקט:


סיכום:
ראינו דרך מהירה ופשוטה לעבודה עם המצלמה ב Android ניתן לממש עוד מגוון רחב של פעולות על המצלמה כמו זיהוי פנים, הוספת גרפיקה על המצלמה , עבודה עם וידאו וכו' (למידע מקיף של Google).

תנו חיוך, מצלמים...