public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); startService(new Intent(this, SynchronizeService.class)); } }
public class SynchronizeService extends Service { private static final int FOREGROUND_NOTIFY_ID = 1; @Override public void onCreate() { super.onCreate(); final NotificationCompat.Builder builder = new NotificationCompat.Builder(this) .setSmallIcon(R.mipmap.ic_launcher) .setContentTitle(getString(R.string.app_name)) .setContentText(getString(R.string.synchronize_service_message)) .setContentIntent(getDummyContentIntent()) .setColor(Color.BLUE) .setProgress(1000, 0, true); startForeground(FOREGROUND_NOTIFY_ID, builder.build()); // CPU PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE); final WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "SynchronizeWakelockTag"); wakeLock.acquire(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { return START_NOT_STICKY; } @Override public IBinder onBind(Intent intent) { return null; } }
dependencies { ... compile 'jcifs:jcifs:1.3.17' }
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="ru.kamisempai.wifisynchronizer"> // . <uses-permission android:name="android.permission.WAKE_LOCK"/> // . <uses-permission android:name="android.permission.INTERNET"/> // SD . <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <application android:label="@string/app_name" android:icon="@mipmap/ic_launcher"> <activity android:name=".activities.MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".services.SynchronizeService"/> </application> </manifest>
public class CopyFilesToSharedFolderTask extends AsyncTask<Void, Double, String> { private final File mFolderToCopy; private final String mSharedFolderUrl; private final NtlmPasswordAuthentication mAuth; private FileFilter mFileFilter; public CopyFilesToSharedFolderTask(File folderToCopy, String sharedFolderUrl, String user, String password, FileFilter fileFilter) { super(); mFolderToCopy = folderToCopy; // , . mSharedFolderUrl = sharedFolderUrl; // Url , . mAuth = (user != null && password != null) ? new NtlmPasswordAuthentication(user + ":" + password) : NtlmPasswordAuthentication.ANONYMOUS; mFileFilter = fileFilter; } }
Special attention should be paid to the user and password parameters. This is the login and password for the network folder that will be used to create NtlmPasswordAuthentication. If you do not need a password to access the folder, NtlmPasswordAuthentication.ANONYMOUS should be used as the authentication. It looks simple, however, authentication is the biggest problem you may encounter when working with network folders. Usually, most problems lurk in improperly setting security policies on a computer. The best way to verify the settings is to try to open the network folder on your phone, through any other file manager that supports networking. private double mMaxProgress; private double mProgress; ... @Override protected String doInBackground(Void... voids) { mMaxProgress = getFilesSize(mFolderToCopy); mProgress = 0; publishProgress(0d); try { SmbFile sharedFolder = new SmbFile(mSharedFolderUrl, mAuth); if (sharedFolder.exists() && sharedFolder.isDirectory()) { copyFiles(mFolderToCopy, sharedFolder); } } catch (MalformedURLException e) { return "Invalid URL."; } catch (IOException e) { e.printStackTrace(); return e.getMessage(); } return null; }
The doInBackground method returns an error message. If null is returned, then everything went smoothly and without errors. private double getFilesSize(File file) { if (!checkFilter(file)) return 0; if (file.isDirectory()) { int size = 0; File[] filesList = file.listFiles(); for (File innerFile : filesList) size += getFilesSize(innerFile); return size; } return (double) file.length(); } private boolean checkFilter(File file) { return mFileFilter == null || mFileFilter.accept(file); }
The filter passed to the designer helps to eliminate unnecessary files and folders. For example, you can exclude all folders starting with a dot or add the Android folder to the blacklist. private static final String LOG_TAG = "WiFiSynchronizer"; private void copyFiles(File fileToCopy, SmbFile sharedFolder) throws IOException { if (!checkFilter(fileToCopy)) return; // , . if (fileToCopy.exists()) { if (fileToCopy.isDirectory()) { File[] filesList = fileToCopy.listFiles(); // "/". SmbFile newSharedFolder = new SmbFile(sharedFolder, fileToCopy.getName() + "/"); if (!newSharedFolder.exists()) { newSharedFolder.mkdir(); Log.d(LOG_TAG, "Folder created:" + newSharedFolder.getPath()); } else Log.d(LOG_TAG, "Folder already exist:" + newSharedFolder.getPath()); for (File file : filesList) copyFiles(file, newSharedFolder); // } else { SmbFile newSharedFile = new SmbFile(sharedFolder, fileToCopy.getName()); // , . // , , , . if (!newSharedFile.exists()) { copySingleFile(fileToCopy, newSharedFile); Log.d(LOG_TAG, "File copied:" + newSharedFile.getPath()); } else Log.d(LOG_TAG, "File already exist:" + newSharedFile.getPath()); // . mProgress += (double) fileToCopy.length(); publishProgress(mProgress / mMaxProgress * 100d); } } } // . private void copySingleFile(File file, SmbFile sharedFile) throws IOException { IOException exception = null; InputStream inputStream = null; OutputStream outputStream = null; try { outputStream = new SmbFileOutputStream(sharedFile); inputStream = new FileInputStream(file); byte[] bytesBuffer = new byte[1024]; int bytesRead; while ((bytesRead = inputStream.read(bytesBuffer)) > 0) { outputStream.write(bytesBuffer, 0, bytesRead); } } catch (IOException e) { exception = e; } finally { if (inputStream != null) try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } if (outputStream != null) try { outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if (exception != null) throw exception; }
private static final int FOREGROUND_NOTIFY_ID = 1; private static final int MESSAGE_NOTIFY_ID = 2; private static final String SHARED_FOLDER_URL = "file://192.168.0.5/shared/"; ... final File folderToCopy = getFolderToCopy(); CopyFilesToSharedFolderTask task = new CopyFilesToSharedFolderTask(folderToCopy, SHARED_FOLDER_URL, null, null, null) { @Override protected void onProgressUpdate(Double... values) { builder.setProgress(100, values[0].intValue(), false) .setContentText(String.format("%s %.3f", getString(R.string.synchronize_service_progress), values[0]) + "%"); mNotifyManager.notify(FOREGROUND_NOTIFY_ID, builder.build()); } @Override protected void onPostExecute(String errorMessage) { stopForeground(true); if (errorMessage == null) showNotification(getString(R.string.synchronize_service_success), Color.GREEN); else showNotification(errorMessage, Color.RED); stopSelf(); wakeLock.release(); // wakeLock } @Override protected void onCancelled(String errorMessage) { // . , - . // . stopSelf(); wakeLock.release(); } }; task.execute();
In my case, the username and password are not required, I did not specify a filter either. The onProgressUpdate method is overridden to show the progress status, and onPostExecute shows a message about the end of the download, or about the occurrence of an error, and then terminates the service.Source: https://habr.com/ru/post/261419/
All Articles