Now open your Eclipse and create a new project. The project name will be FolderLock. For this Folder Locker app, its interface is simple as the File Lokcer interface. We need one EditText to allow the user to input the password, two Buttons for locking and unlocking the folder and one ListView to display the list of files and directories for the user to choose. These components are defined int he activity_main.xml file that is the resource file of the MainActivity class. Its content is shown below.
activity_main.xml file
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android: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=".MainActivity"
android:orientation="vertical"
android:background="@drawable/back_style"
>
<EditText
android:id="@+id/txt_input"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:hint="@string/txt_hint"
/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<Button
android:id="@+id/bt_lock"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/label_lock"
android:onClick="lockFolder"
/>
<Button
android:id="@+id/bt_unlock"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/label_unlock"
android:onClick="unlockFolder"
/>
</LinearLayout>
<TextView
android:id="@+id/txt_view"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<ListView
android:id="@+id/files_list"
android:layout_width="fill_parent"
android:layout_height="300dp"
android:paddingBottom="5dp"
android:paddingTop="5dp"
/>
</LinearLayout>
The file that applies background style to the interface is called back_style.xml. It is saved in the drawable directory of the project.
back_style.xml file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<gradient
android:startColor="#000000"
android:endColor="#000000"
android:angle="270" />
<stroke
android:width="1dp"
android:color="#171717" />
<corners
android:radius="4dp" />
<padding
android:left="10dp"
android:top="10dp"
android:right="10dp"
android:bottom="10dp" />
</shape>
</item>
</selector>
In the drawable directory you also need to have three small image files. One is file icon image. One is directory icon. And the last one is the icon image to represent the locked folder. You can download these images from here.
The string values that are used in the activity_main.xml file are defined in the strings.xml file. This is the content of the strings.xml file.
strings.xml file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">FolderLock</string>
<string name="action_settings">Settings</string>
<string name="label_lock">Lock</string>
<string name="txt_hint">Enter password</string>
<string name="label_unlock">Unlock</string>
<string name="icon_image">Icon</string>
</resources>
Again, we need to customize the ListView to display both images and text. This can be accomplished by defining the components for each item of the ListView in its layout file. Then you need to customize the ArrayAdapter class to supply both images and text to the ListView. You will have a class that extends the ArrayAdapter class. The object of the class will be the data source of the ListView. Here are the content of the listlayout.xml file and ListAdapterModel. java file. The ListAdaperModel stored in the ListAdapterModel.java file extends the ArrayAdapter class.
listlayout.xml file
<?xml version="1.0" encoding="utf-8"?>
<!-- Single List Item Design -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="5dip" >
<ImageView
android:id="@+id/icon"
android:layout_width="30dp"
android:layout_height="30dp"
android:padding="5sp"
android:contentDescription="icon_image"
/>
<TextView
android:id="@+id/label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10sp"
android:textSize="20sp"
android:textColor="#0000ff"
android:textStyle="bold" >
</TextView>
</LinearLayout>
ListAdapterModel.java file
package com.example.folderlock;
import java.io.File;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
public class ListAdapterModel extends ArrayAdapter<String>{
int groupid;
String[] names;
Context context;
String path;
public ListAdapterModel(Context context, int vg, int id, String[] names, String parentPath){
super(context,vg, id, names);
this.context=context;
groupid=vg;
this.names=names;
this.path=parentPath;
}
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View itemView = inflater.inflate(groupid, parent, false);
ImageView imageView = (ImageView) itemView.findViewById(R.id.icon);
TextView textView = (TextView) itemView.findViewById(R.id.label);
String item=names[position];
textView.setText(item);
File lockedfile=new File(context.getFilesDir(),item);
if(lockedfile.exists()){
//set the locked icon to the folder that was already locked.
imageView.setImageDrawable(context.getResources().getDrawable(R.drawable.folder_lock));
}
else{//set the directory and file icon to the unlocked files and folders
File f=new File(path+"/"+item);
if(f.isDirectory())
imageView.setImageDrawable(context.getResources().getDrawable(R.drawable.diricon));
else
imageView.setImageDrawable(context.getResources().getDrawable(R.drawable.fileicon));
}
return itemView;
}
}
To help in locking and unlocking a folder, we also need a Locker class. The Locker.java file defines a class called Locker. This class contains methods that will be used in locking and unlocking folder processes. You will click this Locker.java to download the complete Locker.java file.
Locking and unlocking the folder is similar to locking and unlocking a file. First you need to package the folder in a single zip file. Please read the post Zipper to learn how to zip and extract files and folders. Then the zip file is encrypted so that it can not be extracted or viewed or extract by other apps. The technique to encrypt and decrypt the zip file here is the same as the technique used in the File Locker app. So you can read the explanation on how to encrypt a file on page File Locker.
Now we take a look at the MainActivity class that is in the MainActivity file. Here is the complete MainActivity.java file of the Folder Locker app.
package com.example.folderlock;
import java.io.File;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
public class MainActivity extends Activity {
private String path="";
private String selectedFile="";
private Context context;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.context=this;
}
protected void onStart(){
super.onStart();
ListView lv=(ListView) findViewById(R.id.files_list);
if(lv!=null){
lv.setSelector(R.drawable.selection_style);
lv.setOnItemClickListener(new ClickListener());
}
path="/mnt";
listDirContents();
}
public void onBackPressed(){
goBack();
}
public void goBack(){
if(path.length()>1){ //up one level of directory structure
File f=new File(path);
path=f.getParent();
listDirContents();
}
else{
refreshThumbnails();
System.exit(0); //exit app
}
}
private void refreshThumbnails(){
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"+ Environment.getExternalStorageDirectory())));
}
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private class ClickListener implements OnItemClickListener{
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//selected item
ViewGroup vg=(ViewGroup)view;
String selectedItem = ((TextView) vg.findViewById(R.id.label)).getText().toString();
path=path+"/"+selectedItem;
//et.setText(path);
listDirContents();
}
}
private void listDirContents(){
ListView l=(ListView) findViewById(R.id.files_list);
if(path!=null){
try{
File f=new File(path);
if(f!=null){
if(f.isDirectory()){
String[] contents=f.list();
if(contents.length>0){
//create the data source for the list
ListAdapterModel lm=new ListAdapterModel(this,R.layout.listlayout,R.id.label,contents,path);
//supply the data source to the list so that they are ready to display
l.setAdapter(lm);
selectedFile=path;
}
else
{
//keep track the parent directory of empty directory
path=f.getParent();
}
}
else{
//capture the selected file path
selectedFile=path;
//keep track the parent directory of the selected file
path=f.getParent();
}
}
}catch(Exception e){}
}
}
public void lockFolder(View view){
EditText txtpwd=(EditText)findViewById(R.id.txt_input);
String pwd=txtpwd.getText().toString();
File f=new File(selectedFile);
if(pwd.length()>0){
if(f.isDirectory()){
BackTaskLock btlock=new BackTaskLock();
btlock.execute(pwd,null,null);
}
else{
MessageAlert.showAlert("It is not a folder.",context);
}
}
else{
MessageAlert.showAlert("Please enter password",context);
}
}
public void startLock(String pwd){
Locker locker=new Locker(context,selectedFile,pwd);
locker.lock();
}
public void unlockFolder(View view){
EditText txtpwd=(EditText)findViewById(R.id.txt_input);
String pwd=txtpwd.getText().toString();
File f=new File(selectedFile);
if(pwd.length()>0){
if(f.isFile()){
if(isMatched(pwd)){
BackTaskUnlock btunlock=new BackTaskUnlock();
btunlock.execute(pwd,null,null);
}
else{
MessageAlert.showAlert("Invalid password or folder not locked",context);
}
}
else{
MessageAlert.showAlert("Please select a locked folder to unlock",context);
}
}
else{
MessageAlert.showAlert("Please enter password",context);
}
}
public boolean isMatched(String pwd){
boolean mat=false;
Locker locker=new Locker(context, selectedFile, pwd);
byte[] pas=locker.getPwd();
int pwdRead=locker.bytearrayToInt(pas);
int pwdInput=locker.bytearrayToInt(pwd.getBytes());
if(pwdRead==pwdInput) mat=true;
return mat;
}
private class BackTaskLock extends AsyncTask<String,Void,Void>{
ProgressDialog pd;
protected void onPreExecute(){
super.onPreExecute();
//show process dialog
pd = new ProgressDialog(context);
pd.setTitle("Locking the folder");
pd.setMessage("Please wait.");
pd.setCancelable(true);
pd.setIndeterminate(true);
pd.show();
}
protected Void doInBackground(String...params){
try{
startLock(params[0]);
}catch(Exception e){
pd.dismiss(); //close the dialog if error occurs
}
return null;
}
protected void onPostExecute(Void result){
pd.dismiss();
goBack();
}
}
public void startUnlock(String pwd){
Locker locker=new Locker(context,selectedFile,pwd);
locker.unlock();
}
private class BackTaskUnlock extends AsyncTask<String,Void,Void>{
ProgressDialog pd;
protected void onPreExecute(){
super.onPreExecute();
//show process dialog
pd = new ProgressDialog(context);
pd.setTitle("Unlocking the folder");
pd.setMessage("Please wait.");
pd.setCancelable(true);
pd.setIndeterminate(true);
pd.show();
}
protected Void doInBackground(String...params){
try{
startUnlock(params[0]);
}catch(Exception e){
pd.dismiss(); //close the dialog if error occurs
}
return null;
}
protected void onPostExecute(Void result){
pd.dismiss();
listDirContents();//refresh the list
}
}
}
The content of the MainActivity.java file in the Folder Locker app is nearly the sample as the content of the MainActivity.java file in the File Locker app, except that the lockFile and unlockFile methods are changed to lockFolder to unlockFolder.
Again, in the onStart method of MainActivity class, the ListView component is registered to the item click event so that the ListView is responsive and update its contents when its item is selected. The listDirContents method is invoked to display files and directories in the /mnt directory. The selection style of the list is defined by the selection_style.xml file that is stored in the drawable directory.
selection_style.xml file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<gradient
android:startColor="#dfdfdf"
android:endColor="#dfdfdf"
android:angle="180" />
</shape>
</item>
</selector>
The lockFolder and unlockFoler methods are called when the user pushes the Lock and Unlock buttons. The locking and unlocking folder processes are wrapped in the AsncTask classes so that they can be performed in background without locking the user interface.
Before running the Folder Locker app, you need to take a look at the MessageAlert class. Simply, this class has the showAlert method to display the alert message to the user when he/she does not enter the password before locking or unlocking the folder, when the incorrect password is entered to unlocked the folder, and when the user tries to select a file instead of a folder to lock. The Folder Locker does allow the user to lock folder only.
MessageAlert.java file
package com.example.folderlock;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
public class MessageAlert {
//This method will be invoked to display alert dialog
public static void showAlert(String message,Context context){
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(message);
builder.setCancelable(true);
builder.setPositiveButton("OK", new OnClickListener(){
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
}