Biometric Authentication adalah analisis authentifikasi yang sumbernya adalah data biologis seperti fingerprint jari atau iris mata. Di dalam Pass SDK terdapat beberapa proses yang dapat digunakan untuk melakukan proses identifikasi secara biometric yang datanya diambil dari fingerprint device Samsung.
Beberapa manfaat yang bisa didapatkan dengan menggunakan biometric authentication adalah:
đź’» Mulai Belajar Pemrograman
Belajar pemrograman di Dicoding Academy dan mulai perjalanan Anda sebagai developer profesional.
Daftar Sekarang- Meningkatkan security pada aplikasi.
- Memberikan proses user identifikasi yang lebih nyaman.
Beberapa fitur yang bisa dilakukan oleh Pass SDK adalah:
- Request fingerprint recognition.
- Cancel fingerprint recognition requests.
- Memverifikasi apakah inputan fingerprint cocok dengan fingerprint yang teregistrasi di device.
- Register fingerprint menggunakan Enroll Screen.
- Mendapatkan index dari fingerprint yang teridentifikasi.
- Mendapatkan nama atau unique id dari fingerprint yang sudah pernah diregistrasikan.
- Menset index fingerprint yang bisa di terima ketika request.
- Menambahkan title pada user interface fingerprint.
- Menambahkan logo ikon pada user interface fingerprint.
- Mengubah transparansi pada user interface fingerprint.
- Mendeteksi touch di luar interface fingerprint untuk menutup interface fingerprint.
- Broadcast action ketika terjadi perbuahan pada fingerprint yang sudah diregistrasi.
- Mendapatkan guide untuk kualitas yang tidak bagus pada saat request fingerprint.
- Set tombol pada user interface fingerprint.
- Mengubah standby string pada user interface fingerprint.
Device Support
Untuk devices yang support Biometric Authentication tentunya adalah device Samsung yang memiliki sensor dan sensor fingerprint dengan API minimal 17 Jelly Bean (Android 4.2).
Latihan
Fingerprint telah di manfaatkan oleh beberapa aplikasi yang bisa kalian temukan di Samsung Apps seperti 1Password, LastPass, PayPal, dan lain sebagainya. Kali ini kita langsung saja praktik membuat aplikasi sederhana menggunakan Samsung Pass SDK. Kelas yang akan kita gunakan untuk semua hal yang berhubungan dengan Pass SDK adalah Pass yang di dalamnya terdapat beberapa method untuk inisialisasi Pass SDK, mendapatkan Pass version number dan name, mengecek ketersediaan fitur, dll. Proses inisialisasi perlu dilakukan sekali agar kita dapat mengetahui apakah Pass SDK dapat berjalan pada device tersebut.
Langsung saja kita mulai dengan mengikuti langkah-langkah berikut:
- Buat Project baru dan beri nama PassSample.
Pastikan kamu telah memasukkan library Pass SDK ke dalam project kamu. Untuk instalasi Samsung SDK dan cara memasukkan library SDK terkait ke dalam project telah kita bahas di artikel sebelumnya (https://www.dicoding.com/blog/tutorial-samsung-galaxy-sdk-instalasi/) - Buat file dimens.xml (letaknya di res -> values), fungsi dari file dimens ini untuk mengatur default margin yang akan digunakan untuk mengatur tampilan layout selanjutnya. Kita bisa sesuaikan isinya dengan code di bawah ini:
12345<resources><!-- Default screen margins, per the Android Design guidelines. --><dimen name="activity_horizontal_margin">16dp</dimen><dimen name="activity_vertical_margin">16dp</dimen></resources>
Dari code di atas kita menentukan batas margin vertical dan horizontal masing-masing sebesar 16dp, nantinya kita tinggal panggil nilai dari dimen ini ke dalam tampilan layout kita.
- Modifikasi tampilan layout main_activity.xml seperti di bawah ini :
12345678910111213141516171819202122232425262728293031323334353637<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context="com.dicoding.dhahedda.passsample.MainActivity"><TextViewandroid:id="@+id/textView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Ini adalah aplikasi rahasia"android:textSize="24dp"android:layout_centerHorizontal="true"/><Buttonandroid:id="@+id/btn_secret"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Secret"android:layout_centerVertical="true"android:layout_centerHorizontal="true" /><Buttonandroid:id="@+id/btn_setting"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerHorizontal="true"android:layout_alignParentBottom="true"android:text="Security Setting" /></RelativeLayout>Dari tampilan yang kita buat di atas, tombol “SECRET” akan di gunakan untuk berpindah ke activity lain dengan menggunakan fingerprint sebagai authentication-nya. Sedangkan tombol “SECURITY SETTING”, seperti namanya, tombol ini akan di gunakan untuk berpindah ke activity yang akan kita gunakan untuk mengatur aktivitas Pass SDK.
- Selanjutnya buatlah Activity baru dengan nama SecretActivity. Seperti yang telah di jelaskan sebelumnya, activity ini berfungsi untuk mengecek apakah proses authentifikasi fingerprint sudah berjalan dengan benar. Pada halaman layoutnya tampilannya bisa kalian sesuaikan dengan seperti contoh tampilan di bawah ini:
123456789101112131415<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.dicoding.dhahedda.passsample.SecretActivity"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="24sp"android:layout_centerHorizontal="true"android:layout_centerVertical="true"android:text="Finger Recognition BERHASIL !"/></RelativeLayout> - Buatlah activity baru lagi dengan nama SettingPassActivity. Activity ini nantinya akan kita gunakan sebagai UI untuk mengatur konfigurasi Fingerprint kita. Seperti biasa sesuaikan tampilan layoutnya seperti di bawah ini:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context="com.dicoding.dhahedda.passsample.SettingPassActivity"><LinearLayoutandroid:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_alignParentTop="true"android:layout_alignParentEnd="true"><ScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical" ><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="horizontal"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"android:paddingBottom="@dimen/activity_vertical_margin"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Fingerprint Active"android:textSize="24sp"android:layout_alignParentLeft="true"android:layout_centerVertical="true"android:textColor="@android:color/black"/><Switchandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/switch_active"android:layout_centerVertical="true"android:layout_alignParentRight="true"/></RelativeLayout><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"android:paddingBottom="@dimen/activity_vertical_margin"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Identify With UI"android:textSize="24sp"android:textColor="@android:color/black"android:layout_alignParentLeft="true"android:layout_centerVertical="true"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/btn_identify_with_ui"android:text="start"android:enabled="false"android:layout_alignParentTop="true"android:layout_alignParentEnd="true"></Button></RelativeLayout><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"android:paddingBottom="@dimen/activity_vertical_margin"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Identify Without UI"android:textSize="24sp"android:layout_alignParentLeft="true"android:layout_centerVertical="true"android:textColor="@android:color/black"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerVertical="true"android:layout_alignParentRight="true"android:id="@+id/btn_identify_without_ui"android:text="start"android:enabled="false"></Button></RelativeLayout><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"android:paddingBottom="@dimen/activity_vertical_margin"><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="Register Finger"android:textSize="24sp"android:layout_alignParentLeft="true"android:layout_centerVertical="true"android:textColor="@android:color/black"/><Buttonandroid:id="@+id/btn_fingerregister"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentRight="true"android:layout_centerVertical="true"android:enabled="false"android:text="register"></Button></RelativeLayout><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"android:paddingBottom="@dimen/activity_vertical_margin"><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="Set Intended Finger"android:textSize="24sp"android:layout_alignParentLeft="true"android:layout_centerVertical="true"android:textColor="@android:color/black"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerVertical="true"android:layout_alignParentRight="true"android:id="@+id/btn_show_intended_finger"android:text="select"android:enabled="false"></Button></RelativeLayout></LinearLayout></ScrollView></LinearLayout></RelativeLayout> - Sekarang buat kelas baru dan beri nama PassPreferences, sesuaikan codenya sebagai berikut:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849public class PassPreferences {private String PREFS_NAME = "PassPrefs";private String KEY_ACTIVE = "PassActive";private String KEY_DESIGNATED = "PassDesignated";private SharedPreferences preferences;private SharedPreferences.Editor editor;private String TAG = "PREFERENCES TAG";public PassPreferences(Context context){preferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);editor = preferences.edit();}public void setActive(boolean active){editor.putBoolean(KEY_ACTIVE, active);editor.apply();}public Boolean getActive(){return preferences.getBoolean(KEY_ACTIVE, false);}public void setDesignated(Integer[] input){StringBuilder str = new StringBuilder();for (int i = 0; i < input.length; i++) {str.append(input[i]).append(",");}editor.putString(KEY_DESIGNATED, str.toString());editor.apply();}public Integer[] getDesignated(){String savedString = preferences.getString(KEY_DESIGNATED, "");Log.d(TAG, "getDesignated: saved string "+savedString);if (savedString == "") return new Integer[0];String[] designatedStringArr= savedString.split(",");Integer[] designatedIntArr = new Integer[designatedStringArr.length];Log.d(TAG, "getDesignated: "+designatedStringArr.length);for (int i = 0 ; i < designatedStringArr.length ; i++){designatedIntArr[i] = Integer.parseInt(designatedStringArr[i]);}return designatedIntArr;}} - Selanjutnya kita buat satu kelas baru lagi dengan nama MyPass. Kelas ini yang nantinya akan kita gunakan untuk semua hal yang berhubungan dengan Pass SDK, bisa dibilang kelas MyPass.java ini merupakn pusat pengaturan dari aplikasi PassSample ini. Modifikasi isi codenya menjadi seperti berikut:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443public class MyPass implements Handler.Callback {private SpassFingerprint mSpassFingerprint;private Spass mSpass;private boolean isFeatureEnabled;private String TAG = "Test Pass";private Context context;private MyPassCallback myPassCallback;private PassPreferences passPrefs;public boolean isFeatureEnabled_index = false;public boolean isFeatureEnabled_custom = false;public boolean isFeatureEnabled_uniqueId = false;public boolean isFeatureEnabled_backupPw = false;public boolean hasRegisteredFinger = false;private static final int MSG_AUTH_DIALOG = 1000;private static final int MSG_AUTH_WITHOUT_DIALOG = 1002;private static final int MSG_REGISTER = 1003;private static final int MSG_CANCEL = 10004;private String MSG_BUNDLE = "msg_bundle";private Handler mHandler;public MyPass(Context context){mSpass = new Spass();this.context = context;passPrefs = new PassPreferences(context);mHandler = new Handler(this);}public void setCallback(MyPassCallback myPassCallback){this.myPassCallback = myPassCallback;}public boolean initialize() throws SsdkUnsupportedException,UnsupportedOperationException{mSpass.initialize(context);isFeatureEnabled = mSpass.isFeatureEnabled(Spass.DEVICE_FINGERPRINT);if(isFeatureEnabled){mSpassFingerprint = new SpassFingerprint(context);checkAvalailableFeatures();checkRegistered();} else {return false;}return true;}private void checkAvalailableFeatures(){isFeatureEnabled_index = mSpass.isFeatureEnabled(Spass.DEVICE_FINGERPRINT_FINGER_INDEX);isFeatureEnabled_custom = mSpass.isFeatureEnabled(Spass.DEVICE_FINGERPRINT_CUSTOMIZED_DIALOG);isFeatureEnabled_uniqueId = mSpass.isFeatureEnabled(Spass.DEVICE_FINGERPRINT_UNIQUE_ID);isFeatureEnabled_backupPw = mSpass.isFeatureEnabled(Spass.DEVICE_FINGERPRINT_AVAILABLE_PASSWORD);}//Menyimpan kondisi aktif security di dalam shared preferencespublic void setActive(boolean active){passPrefs.setActive(active);}public boolean getActive(){return passPrefs.getActive();}//Menyimpan data designated index di dalam shared preferencespublic void setDesignatedIndex(Integer[] input){passPrefs.setDesignated(input);}public Integer[] getDesignatedIndex(){return passPrefs.getDesignated();}public void identifyByIndex(){Integer[] designatedArray = getDesignatedIndex();//Karena intendedFingerPrint dimulai dari index ke 1 maka perlu di sesuaikan pada default index 0for(int i = 0 ; i < designatedArray.length ; i++){designatedArray[i] = designatedArray[i] + 1;}ArrayList<Integer> newDesignatedArray = new ArrayList<>(Arrays.asList(designatedArray));mSpassFingerprint.setIntendedFingerprintIndex(newDesignatedArray);}//Check apakah sudah ada data yang diregistrasipublic void checkRegistered() throws UnsupportedOperationException{hasRegisteredFinger = mSpassFingerprint.hasRegisteredFinger();}//HANDLER REGISTERpublic void handleRegisterFinger(){mHandler.sendEmptyMessage(MSG_REGISTER);}//REGISTER FINGER 1003private void registerFinger(){mSpassFingerprint.registerFinger(context,mRegisterListener);}public CharSequence[] getFingerprintName() {SparseArray<String> fingerSparse= null;List<String> fingerList = new ArrayList<>();fingerSparse = mSpassFingerprint.getRegisteredFingerprintName();if (fingerSparse == null) {Log.d(TAG, "getFingerprintName: ZERO SIZE");return fingerList.toArray(new String[fingerList.size()]);} else {Log.d(TAG, "getFingerprintName: "+fingerSparse.size());for (int i = 0; i < fingerSparse.size(); i++) {int index = fingerSparse.keyAt(i);String name = fingerSparse.get(index);fingerList.add(name);}return fingerList.toArray(new String[fingerList.size()]);}}private boolean onReadyIdentify = false;private boolean needRetryIdentify = false;//HANDLER IDENTIFY FINGERpublic void handleIdentifyWithDialog(boolean designated){Message msg = new Message();msg.what = MSG_AUTH_DIALOG;Bundle bundle = new Bundle();bundle.putBoolean(MSG_BUNDLE,designated);msg.setData(bundle);mHandler.sendMessage(msg);}//IDENTIFY FINGER 1001private void identifyFingerWithDialog(boolean designated){if (onReadyIdentify == false) {onReadyIdentify = true;try {if (mSpassFingerprint != null) {// setIdentifyIndexDialog();//Jika designated true maka request menyesuaikan dengan index yang diinginkanif(designated) {identifyByIndex();}mSpassFingerprint.startIdentifyWithDialog(context, mIdentifyListenerDialog, false);}//if (designatedFingersDialog != null) {// log("Please identify finger to verify you with " + designatedFingersDialog.toString() + " finger");//} else {// log("Please identify finger to verify you");//}} catch (IllegalStateException e) {onReadyIdentify = false;//resetIdentifyIndexDialog();//log("Exception: " + e);}} else {//log("The previous request is remained. Please finished or cancel first");}}//HANDLER IDENTIFY FINGER WITHOUT DIALOGpublic void handleIdentifyWithoutDialog(){mHandler.sendEmptyMessage(MSG_AUTH_WITHOUT_DIALOG);}//IDENTIFY FINGER WITHOUT DIALOG 1002private void identifyFingerWithoutDialog() {Log.d(TAG, "startIdentify: "+onReadyIdentify);if (onReadyIdentify == false) {try {onReadyIdentify = true;if (mSpassFingerprint != null) {//setIdentifyIndex();mSpassFingerprint.startIdentify(mIdentifyListener);}/*if (designatedFingers != null) {log("Please identify finger to verify you with " + designatedFingers.toString() + " finger");} else {log("Please identify finger to verify you");}*/} catch (SpassInvalidStateException ise) {onReadyIdentify = false;//resetIdentifyIndex();if (ise.getType() == SpassInvalidStateException.STATUS_OPERATION_DENIED) {//log("Exception: " + ise.getMessage());Log.d(TAG, "startIdentify: "+ ise.getMessage());}} catch (IllegalStateException e) {onReadyIdentify = false;//resetIdentifyIndex();//log("Exception: " + e);Log.d(TAG, "startIdentify: "+e.getMessage());}} else {//log("The previous request is remained. Please finished or cancel first");}}private SpassFingerprint.RegisterListener mRegisterListener = new SpassFingerprint.RegisterListener() {@Overridepublic void onFinished() {checkRegistered();myPassCallback.onFinishedRegister(hasRegisteredFinger);}};private SpassFingerprint.IdentifyListener mIdentifyListenerDialog = new SpassFingerprint.IdentifyListener() {@Overridepublic void onFinished(int eventStatus) {myPassCallback.onFinishedIdentify(eventStatus);//log("identify finished : reason =" + getEventStatusName(eventStatus));int FingerprintIndex = 0;boolean isFailedIdentify = false;onReadyIdentify = false;try {FingerprintIndex = mSpassFingerprint.getIdentifiedFingerprintIndex();Log.d(TAG, "onFinished: "+FingerprintIndex);} catch (IllegalStateException ise) {// log(ise.getMessage());}if (eventStatus == SpassFingerprint.STATUS_AUTHENTIFICATION_SUCCESS) {//log("onFinished() : Identify authentification Success with FingerprintIndex : " + FingerprintIndex);} else if (eventStatus == SpassFingerprint.STATUS_AUTHENTIFICATION_PASSWORD_SUCCESS) {//log("onFinished() : Password authentification Success");} else if (eventStatus == SpassFingerprint.STATUS_USER_CANCELLED|| eventStatus == SpassFingerprint.STATUS_USER_CANCELLED_BY_TOUCH_OUTSIDE) {// log("onFinished() : User cancel this identify.");} else if (eventStatus == SpassFingerprint.STATUS_TIMEOUT_FAILED) {//log("onFinished() : The time for identify is finished.");} else if (!mSpass.isFeatureEnabled(Spass.DEVICE_FINGERPRINT_AVAILABLE_PASSWORD)) {if (eventStatus == SpassFingerprint.STATUS_BUTTON_PRESSED) {// log("onFinished() : User pressed the own button");//Toast.makeText(mContext, "Please connect own Backup Menu", Toast.LENGTH_SHORT).show();}} else {//log("onFinished() : Authentification Fail for identify");isFailedIdentify = true;}if (!isFailedIdentify) {//resetIdentifyIndexDialog();}}@Overridepublic void onReady() {//log("identify state is ready");}@Overridepublic void onStarted() {//log("User touched fingerprint sensor");}@Overridepublic void onCompleted() {//log("the identify is completed");}};private SpassFingerprint.IdentifyListener mIdentifyListener = new SpassFingerprint.IdentifyListener() {@Overridepublic void onFinished(int eventStatus) {//log("identify finished : reason =" + getEventStatusName(eventStatus));myPassCallback.onFinishedIdentify(eventStatus);int FingerprintIndex = 0;String FingerprintGuideText = null;try {FingerprintIndex = mSpassFingerprint.getIdentifiedFingerprintIndex();} catch (IllegalStateException ise) {//log(ise.getMessage());}if (eventStatus == SpassFingerprint.STATUS_AUTHENTIFICATION_SUCCESS) {//log("onFinished() : Identify authentification Success with FingerprintIndex : " + FingerprintIndex);} else if (eventStatus == SpassFingerprint.STATUS_AUTHENTIFICATION_PASSWORD_SUCCESS) {//log("onFinished() : Password authentification Success");} else if (eventStatus == SpassFingerprint.STATUS_OPERATION_DENIED) {//log("onFinished() : Authentification is blocked because of fingerprint service internally.");} else if (eventStatus == SpassFingerprint.STATUS_USER_CANCELLED) {//log("onFinished() : User cancel this identify.");} else if (eventStatus == SpassFingerprint.STATUS_TIMEOUT_FAILED) {//log("onFinished() : The time for identify is finished.");} else if (eventStatus == SpassFingerprint.STATUS_QUALITY_FAILED) {//log("onFinished() : Authentification Fail for identify.");needRetryIdentify = true;FingerprintGuideText = mSpassFingerprint.getGuideForPoorQuality();Toast.makeText(context, FingerprintGuideText, Toast.LENGTH_SHORT).show();} else {//log("onFinished() : Authentification Fail for identify");needRetryIdentify = true;}if (!needRetryIdentify) {//resetIdentifyIndex();}}@Overridepublic void onReady() {//log("identify state is ready");}@Overridepublic void onStarted() {//log("User touched fingerprint sensor");}@Overridepublic void onCompleted() {//log("the identify is completed");onReadyIdentify = false;Log.d(TAG, "onCompleted: onready "+onReadyIdentify);Log.d(TAG, "onCompleted: need "+needRetryIdentify);if (needRetryIdentify) {needRetryIdentify = false;mHandler.sendEmptyMessageDelayed(MSG_AUTH_WITHOUT_DIALOG, 100);}}};//HANDLER CANCEL IDENTIFYpublic void handleCancelIdentify(){mHandler.sendEmptyMessage(MSG_CANCEL);}//CANCEL FINGER 1004private void cancelIdentify() {if (onReadyIdentify == true) {try {if (mSpassFingerprint != null) {mSpassFingerprint.cancelIdentify();}//log("cancelIdentify is called");} catch (IllegalStateException ise) {//log(ise.getMessage());}onReadyIdentify = false;needRetryIdentify = false;} else {//log("Please request Identify first");}}public static String getEventStatusName(int eventStatus) {switch (eventStatus) {case SpassFingerprint.STATUS_AUTHENTIFICATION_SUCCESS:return "STATUS_AUTHENTIFICATION_SUCCESS";case SpassFingerprint.STATUS_AUTHENTIFICATION_PASSWORD_SUCCESS:return "STATUS_AUTHENTIFICATION_PASSWORD_SUCCESS";case SpassFingerprint.STATUS_TIMEOUT_FAILED:return "STATUS_TIMEOUT";case SpassFingerprint.STATUS_SENSOR_FAILED:return "STATUS_SENSOR_ERROR";case SpassFingerprint.STATUS_USER_CANCELLED:return "STATUS_USER_CANCELLED";case SpassFingerprint.STATUS_QUALITY_FAILED:return "STATUS_QUALITY_FAILED";case SpassFingerprint.STATUS_USER_CANCELLED_BY_TOUCH_OUTSIDE:return "STATUS_USER_CANCELLED_BY_TOUCH_OUTSIDE";case SpassFingerprint.STATUS_BUTTON_PRESSED:return "STATUS_BUTTON_PRESSED";case SpassFingerprint.STATUS_OPERATION_DENIED:return "STATUS_OPERATION_DENIED";case SpassFingerprint.STATUS_AUTHENTIFICATION_FAILED:default:return "STATUS_AUTHENTIFICATION_FAILED";}}@Overridepublic boolean handleMessage(Message message) {switch (message.what) {case MSG_AUTH_DIALOG:boolean designated = message.getData().getBoolean(MSG_BUNDLE);identifyFingerWithDialog(designated);break;case MSG_AUTH_WITHOUT_DIALOG:identifyFingerWithoutDialog();break;case MSG_REGISTER:registerFinger();break;case MSG_CANCEL:cancelIdentify();break;}return true;}}interface MyPassCallback{void onFinishedIdentify(int eventStatus);void onFinishedRegister(boolean register);} - Sekarang kembali ke kelas SettingPassActivity.java, sesuaikan tampilan codenya sebagai berikut:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239public class SettingPassActivity extends AppCompatActivity implements MyPassCallback, View.OnClickListener,CompoundButton.OnCheckedChangeListener {MyPass myPass;Switch switchActive;Button btnIdWithUi, btnIdWithoutUi, btnRegister , btnIntended;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_setting_pass);myPass = new MyPass(this);myPass.setCallback(this);try{myPass.initialize();initButton();if (myPass.getActive()){switchActive.setChecked(true);setEnableButton();}}catch (SsdkUnsupportedException e){showErrorDialog("SDK PASS",e.getMessage());return;}catch (UnsupportedOperationException e){showErrorDialog("OPERATION PASS",e.getMessage());return;}}void initButton(){switchActive = (Switch)findViewById(R.id.switch_active);switchActive.setOnCheckedChangeListener(this);btnIdWithUi = (Button)findViewById(R.id.btn_identify_with_ui);btnIdWithUi.setOnClickListener(this);btnIdWithoutUi = (Button)findViewById(R.id.btn_identify_without_ui);btnIdWithoutUi.setOnClickListener(this);btnRegister = (Button)findViewById(R.id.btn_fingerregister);btnRegister.setOnClickListener(this);btnIntended = (Button)findViewById(R.id.btn_show_intended_finger);btnIntended.setOnClickListener(this);}void setEnableButton(){if (myPass.hasRegisteredFinger) {btnIdWithUi.setEnabled(true);btnIdWithoutUi.setEnabled(true);btnRegister.setEnabled(true);btnIntended.setEnabled(true);}}void setDisableButton(){btnIdWithUi.setEnabled(false);btnIdWithoutUi.setEnabled(false);btnRegister.setEnabled(false);btnIntended.setEnabled(false);}@Overridepublic void onCheckedChanged(CompoundButton compoundButton, boolean enabled) {int id = compoundButton.getId();switch (id){case R.id.switch_active:if(enabled){if (myPass.hasRegisteredFinger){myPass.setActive(true);setEnableButton();Log.d(TAG, "onCheckedChanged: switch already registered");}else {//Change to handlermyPass.handleRegisterFinger();}}else{myPass.setActive(false);setDisableButton();}break;default:break;}}private String TAG = "Setting Pass";@Overridepublic void onFinishedIdentify(int eventStatus) {Log.d(TAG, "onFinishedIdentify: "+eventStatus);Log.d(TAG, "onFinishedIdentify: "+MyPass.getEventStatusName(eventStatus));}@Overridepublic void onFinishedRegister(boolean register) {if(!register) {switchActive.setChecked(false);myPass.setActive(false);setDisableButton();}else{myPass.setActive(true);setEnableButton();}}@Overridepublic void onClick(View view) {int id = view.getId();switch(id){case R.id.btn_identify_with_ui://Change to handlermyPass.handleIdentifyWithDialog(false);break;case R.id.btn_identify_without_ui:setDisableButton();//Change to handlermyPass.handleIdentifyWithoutDialog();break;case R.id.btn_fingerregister://Change to handlermyPass.handleRegisterFinger();break;case R.id.btn_show_intended_finger://Change to handlershowDialogIndex();break;}}ArrayList selectedItems = new ArrayList();void showDialogIndex(){CharSequence[] fingerItems = myPass.getFingerprintName();Integer[] designatedIndex = myPass.getDesignatedIndex();boolean[] fingerChecked = getCheckedIndex(fingerItems,designatedIndex);selectedItems = new ArrayList<>(Arrays.asList(designatedIndex));AlertDialog dialogIndex = new AlertDialog.Builder(SettingPassActivity.this).setTitle("Select designated finger.").setMultiChoiceItems(fingerItems, fingerChecked, new DialogInterface.OnMultiChoiceClickListener() {@Overridepublic void onClick(DialogInterface dialog, int indexSelected, boolean isChecked) {if (isChecked) {// If the user checked the item, add it to the selected itemsselectedItems.add(indexSelected);} else if (selectedItems.contains(indexSelected)) {// Else, if the item is already in the array, remove itselectedItems.remove(Integer.valueOf(indexSelected));}}}).setPositiveButton("OK", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int id) {// Your code when user clicked on OK// You can write the code to save the selected item hereLog.d(TAG, "onClick: "+ selectedItems.toString());if (selectedItems.size() > 0) {Integer[] selectedArray = (Integer[]) selectedItems.toArray(new Integer[selectedItems.size()]);myPass.setDesignatedIndex(selectedArray);}}}).setNegativeButton("Cancel", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int id) {// Your code when user clicked on Cancel}}).create();dialogIndex.show();}boolean[] getCheckedIndex(CharSequence[] input, Integer[] designated){boolean[] checkedIndex = new boolean[input.length];Arrays.fill(checkedIndex,false);for (int i = 0 ; i < designated.length ; i++){if (designated[i] < input.length){checkedIndex[designated[i]] = true;}}return checkedIndex;}void showErrorDialog(String title,String message){new AlertDialog.Builder(this).setTitle(title).setMessage(message).setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {public void onClick(DialogInterface dialog, int which) {SettingPassActivity.this.finish();}}).setIcon(android.R.drawable.ic_dialog_alert).show();}} - Terakhir buka kembali kelas MainActivity.java. Modifikasi code di dalamnya sedemikian rupa seperti contoh di bawah ini:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102public class MainActivity extends AppCompatActivity implements MyPassCallback, View.OnClickListener{MyPass myPass;Button btnSetting,btnSecret;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);myPass = new MyPass(this);myPass.setCallback(this);try {myPass.initialize();}catch (SsdkUnsupportedException e){showErrorDialog("SDK PASS",e.getMessage());return;}catch (UnsupportedOperationException e){showErrorDialog("OPERATION PASS",e.getMessage());return;}btnSecret = (Button)findViewById(R.id.btn_secret);btnSetting = (Button)findViewById(R.id.btn_setting);btnSecret.setOnClickListener(this);btnSetting.setOnClickListener(this);}@Overrideprotected void onResume() {super.onResume();}@Overrideprotected void onPause() {super.onPause();}@Overridepublic void onClick(View view) {int id = view.getId();switch (id){case R.id.btn_secret:if (myPass.getActive()){myPass.handleIdentifyWithDialog(true);}else{showErrorDialog("Fingerprint Activated","You need to activate the fingerprint security..");}break;case R.id.btn_setting:Intent setting = new Intent(MainActivity.this,SettingPassActivity.class);MainActivity.this.startActivity(setting);break;}}void showErrorDialog(String title,String message){new AlertDialog.Builder(this).setTitle(title).setMessage(message).setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {public void onClick(DialogInterface dialog, int which) {}}).setIcon(android.R.drawable.ic_dialog_alert).show();}@Overridepublic void onFinishedIdentify(int eventStatus) {if (eventStatus == SpassFingerprint.STATUS_AUTHENTIFICATION_SUCCESS) {Intent secret = new Intent(MainActivity.this, SecretActivity.class);this.startActivity(secret);}}@Overridepublic void onFinishedRegister(boolean register) {}} - Sekarang silahkan run program.
Pada demo di atas kita mencoba membuka intent pada button “SECRET” dengan menggunakan fingerprint. Yang harus kita lakukan terlebih dahulu adalah masuk ke menu “SECURITY SETTING” dan mengaktifkan fungsi fingerprint. Kita bisa melihat data fingerprint yang telah terdaftar di menu “Set Intended Finger”, di situ juga kita bisa menentukan data sidik jari mana yang akan kita pakai. Untuk mendaftarkan identitas jari yang baru, kita bisa menggunakan menu “Register Finger” kemudian ikuti petunjuk selanjutnya. Kita bisa memastikan sidik jari yang telah di buat bisa di gunakan dengan menu “Identify With UI” dan juga “Identify Without UI”, tetapi pastikan kamu sudah mengaktifkan sidik jari yang akan kamu gunakan pada menu “Set Intended Finger”. Jika sidik jari yang kamu gunakan match (sesuai) dengan sidik jari yang telah di daftarkan maka kita bisa membuka halaman “SECRET” yang ingin kita tuju sebelumnya.
Bagaimana, ada kesulitan? Penjelasan tentang method-method yang digunakan pada latihan kali ini bisa kalian lihat dan pelajari di Dicoding Academy (https://www.dicoding.com/academies/37). Jika ada pertanyaan, saran atau masukan jangan sungkan untuk menuliskannya di kolom komentar.
Selamat belajar, semoga bermanfaat, dan nantikan tutorial Samsung Galaxy SDK selanjutnya.