📜 ⬆️ ⬇️

We place the files from Assets to the SD card using Infles

Good day, Habravchane!

Description:


Almost all users of the Android OS know the practice of applications using files from an SD card.
Most applications download these files from the Internet and put them in their own folder, but not all users have the opportunity to download them from the network and not all developers have their own server, but you will not be comfortable with copying files manually.
Therefore, in order to make life easier for everyone, the program “Infles” was written, it is distributed free of charge with open source code and under the MIT license. The program allows in 1 click to install the necessary files in the folder specified in the settings on the SD card. To do this, put them in the “assets” folder, in the code in the file "\ Infles \ src \ ru \ boomik \ infles \ InflesActivity.java" in the variable "COPY_DIR" specify the path on the memory card and compile the program.

The idea of ​​the program appeared just when using the application, for access to all the possibilities of which it was necessary to copy the files to a flash drive in a specific folder, but there was no built-in mechanism.
')



And now about the creation and code.


The application turned out to be simple, and this is its goal - simplicity and ease of use. It consists of only 2 classes, activity and service (for greater stability). The service does not have anything sensible, but we will analyze the activation, it just contains all the functions (at the end of the article I will provide links to the source code and an example application).
Layout (layer) of the application contains 4 buttons - one large, almost the entire screen and 3 additional (which can be hidden by changing the value of SHOW_BUTTON to false).
Activiti contains a number of features that will be discussed below.
The code is not complicated, but I will explain everything point by point. Pieces of code will go in turn, as they are located in the class itself.

package ru.boomik.infles; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import android.app.Activity; import android.app.Dialog; import android.app.ProgressDialog; import android.content.Intent; import android.content.res.AssetManager; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.text.Html; import android.text.method.LinkMovementMethod; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; public class InflesActivity extends Activity { private static final String LOG_TAG = "Infles:InflesActivity"; private static final int ABOUT = 1; private static final int PROGRESS = 2; boolean resCopy; String[] wrong = { "images", "sounds", "webkit" }; // boolean SHOW_BUTTON = true; boolean UNZIP = false; boolean DEL_ZIP = false; String COPY_DIR = "Infles"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //  Button ActButton = (Button)findViewById(R.id.ActButton); ImageButton Exit = (ImageButton)findViewById(R.id.exit); ImageButton About = (ImageButton)findViewById(R.id.about); ImageButton Delete = (ImageButton)findViewById(R.id.delete); // Listener' ActButton.setOnClickListener(ActListener); Exit.setOnClickListener(ExitListener); About.setOnClickListener(AboutListener); Delete.setOnClickListener(DeleteListener); // ,  SHOW_BUTTON = false if (!SHOW_BUTTON) { Exit.setVisibility(View.GONE); About.setVisibility(View.GONE); Delete.setVisibility(View.GONE); } } 

We perform the necessary imports, declare the class "InflesActivity" and the variables necessary for the work of the program, and under them the settings.

boolean SHOW_BUTTON = true; - display additional buttons on the screen;
boolean UNZIP = false; - unpack zip archives;
boolean DEL_ZIP = false; - delete zip archives (only when the decompression option is enabled);
String COPY_DIR = "Infles"; - the path to the SD card. "/" at the beginning and end do not put.

In the onCreate function, all buttons are first defined (ActButton, Delete, About, Exit), then assigned to the Listener buttons and the SHOW_BUTTON variable is checked and if it is false, then the buttons are hidden.

  private OnClickListener ActListener = new OnClickListener() { public void onClick(View v) { showDialog(PROGRESS); //  - startService(new Intent(InflesActivity.this,InflesService.class)); final String dir="/"+COPY_DIR+"/"; final String sdDir="/sdcard" +dir; final AssetManager am = getAssets(); //   Assets //  new Thread(new Runnable() { public void run() { try { String[] files = am.list(""); for(int i=0; i<files.length; i++) { if (!CheckMass(files[i],wrong)) { dirChecker(dir); // checking directory copy(files[i],dir); if (UNZIP) { String filename = files[i]; int dotPos = filename.lastIndexOf("."); String ext = filename.substring(dotPos); //   if (ext.equals(".zip")) { File File = new File(Environment.getExternalStorageDirectory()+ dir + filename); if (File.exists()) { unzip(File,sdDir,dir); if (DEL_ZIP) { File.delete(); } } else Log.i(LOG_TAG, dir + filename+" not exists"); } } } } } catch (IOException e1) { e1.printStackTrace(); } InflesActivity.this.runOnUiThread(new Runnable() { public void run() { dismissDialog(PROGRESS); // - } }); } }).start(); exit(); DeleteApp(); } }; 


Handler pressing the "RUN!" Button. First, the progress dialog is invoked (code further), then new variables are declared for use in the program. After that, the new stream reads all the files from the Assets folder, for which the variable “am” of the type “AssetManager” was declared. Then, using the CheckMass () function, we check if there is a file in the blacklist of names (for some reason, when reading the Assets folder, there are left folders, I haven’t figure out the reason yet, but we discard them); there is no such thing, it is created, and then the actual copying of files takes place by the “copy ()” function. The next section of the code checks whether the option of extracting archives is enabled, and if so, then files are checked by extension, and if it finds them, extracts them from to the current folder (the “Unzip ()” function). The archive may contain subfolders, which is demonstrated in the example, if just in the Assets folder there is a subfolder — it is not copied, I will look for a solution. Next, the dialog, the flow, the program are closed and the program deletion dialog is called - its function has completed and there is no sense to store it, although you can click Cancel and it will remain.

  //   private OnClickListener ExitListener = new OnClickListener() { public void onClick(View v) { exit(); } }; private OnClickListener AboutListener = new OnClickListener() { public void onClick(View v) { showDialog(ABOUT); } }; private OnClickListener DeleteListener = new OnClickListener() { public void onClick(View v) { exit(); DeleteApp(); } }; private void exit() { finish(); stopService(new Intent(InflesActivity.this,InflesService.class)); } private void DeleteApp() { Uri packageURI = Uri.parse("package:ru.boomik.infles"); Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI); startActivity(uninstallIntent); } 


Here the listeners of the remaining three additional buttons that call their functions are executed. The showDialog (ABOUT) function calls the About dialog, the Exit () function closes the activation and stops the service, and the DeleteApp () function opens the application uninstall dialog.

  protected Dialog onCreateDialog(int id) { //  super.onCreateDialog(id); switch(id) { case ABOUT: // " " //Context mContext = getApplicationContext(); Dialog dialog = new Dialog(this); dialog.setContentView(R.layout.about); dialog.setTitle("About"); TextView text = (TextView) dialog.findViewById(R.id.text); text.setText(Html.fromHtml("Infles - programm from copy files from app to SD card.<br /><br />Author: Kirill \"BOOM\" Ashikhmin<br />Email: <a href=\"mailto:boom.vrn@gmail.com\">boom.vrn@gmail.com</a><br />Site: <a href=\"http://boomik.ru\">http://boomik.ru</a><br />Source: <a href=\"http://code.google.com/p/infles/\">http://code.google.com/p/infles/</a><br /><br />License: MIT.")); text.setMovementMethod(LinkMovementMethod.getInstance()); ImageView image = (ImageView) dialog.findViewById(R.id.image); image.setImageResource(R.drawable.icon); return dialog; case PROGRESS: //   ProgressDialog dialogPr = new ProgressDialog(this); dialogPr.setTitle("Please, wait..."); dialogPr.setMessage("Copying files..."); dialogPr.setIndeterminate(true); return dialogPr; default: dialog = null; } return null; } 

This function is called when the dialog "About the program" and the progress-dialogue are opened. A variable of the “int” type is passed to the function and based on it the corresponding dialog is called. I will describe the dialogues themselves - there are already a lot of articles on the Internet, and there is a good example on developer.android.com. I can only say that for the window “About the program” my xml layout is used and the text is output from the code and output as html code to support links.



  private boolean copy(String fileName, String dir) { try { AssetManager am = getAssets(); File destinationFile = new File(Environment.getExternalStorageDirectory()+ dir + fileName); // InputStream in = am.open(fileName); //   FileOutputStream f = new FileOutputStream(destinationFile); byte[] buffer = new byte[1024]; int len1 = 0; while ((len1 = in.read(buffer)) > 0) { f.write(buffer, 0, len1); } f.close(); resCopy=true; } catch (Exception e) { Log.d(LOG_TAG, e.getMessage()); resCopy=false; } return resCopy; } 

This is the main function of the program — copying files, and even then there is nothing extremely complicated; a reference to the file appears in the destinationFile variable, then the file is opened and copied in 1 kB slice.
  public void unzip(File zip,String location,String dir) //   { Log.i(LOG_TAG,zip +" unzipped"); try { FileInputStream fin = new FileInputStream(zip); ZipInputStream zin = new ZipInputStream(fin); ZipEntry ze = null; while ((ze = zin.getNextEntry()) != null) { if(ze.isDirectory()) { dirChecker(dir+ze.getName()); } else { FileOutputStream fout = new FileOutputStream(location + ze.getName()); for (int c = zin.read(); c != -1; c = zin.read()) { fout.write(c); } zin.closeEntry(); fout.close(); } } zin.close(); } catch(Exception e) { } } 

Zip archives extraction function. It uses the standard Java language function for working with archives.
  private void dirChecker(String dir) { File Directory = new File("/sdcard"+dir); Log.i(LOG_TAG,"/sdcard"+dir +" - dir check"); if(!Directory.isDirectory()) { Directory.mkdirs(); } } static public boolean CheckMass(String text, String[] arr) { boolean res=false; int strLenght=arr.length; for (int i=0;i<strLenght;i++){ if (text.equals(arr[i])){ res=true; break; }} return res; } 

Two small functions for checking the creation of a folder, if there is no such, and searching for the value of a variable in an array, for the black list of files.
  @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu, menu); //   menu.xml return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.delete: exit(); DeleteApp(); return true; case R.id.about: showDialog(ABOUT); return true; case R.id.exit: exit(); return true; } return super.onOptionsItemSelected(item); } } 


Well, here a menu is displayed, which is invoked, as you can guess, from the hard enopka “Menu” on any Android device.

The layout files and menus are the simplest, so I’ll not give them in the article - who are interested in asking SVN to view the code and study the example.

If you have any suggestions for the program, or suggestions how to improve the code - write, I will try to implement.
Once again I remind you that the program is absolutely free, you can use with your projects without restrictions, but it is desirable to leave the original name and the window “About the program”.

Difficulties


The first difficulty was associated with the addresses of the paths, in different places I had to describe them in different ways.
The second was the inability to create subfolders, decided by the introduction of extract from the archive.
The third is not the ability to set the Russian name of the file or folder. Not yet decided, and is it worth it?
The fourth problem I do not know where it came from and how - hidden files without an extension in the Assets folder, for which the filter is applied.

Links


Project code on SVN: code.google.com/p/infles
Example of the program: infles.googlecode.com/files/Infles.apk
(Copies the file "Infles.txt" into the folder "Infles" and extracts the archive with the file "Infles from zip.txt" and the folder "Subfolder from zip", which in turn contains the file "Infles from subfolder zip.txt")

PS Changed the license for MIT, cleaned the source code in the repository.

Source: https://habr.com/ru/post/123457/


All Articles