/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.autobackupsample;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Toast;
import com.example.android.autobackupsample.MainActivityFragment;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
/**
* The purpose of AddFileActivity activity is to create a data file based on the
* file name and size parameters specified as an Intent external parameters or with the
* activity UI.
* <p/>
* The optional intent parameters are
* {@link com.example.android.autobackupsample.AddFileActivity#FILE_NAME} and
* {@link com.example.android.autobackupsample.AddFileActivity#FILE_SIZE_IN_BYTES}.
* {@link com.example.android.autobackupsample.AddFileActivity#FILE_STORAGE}.
* <p/>
* The activity will return an
* {@link com.example.android.autobackupsample.MainActivityFragment#ADD_FILE_RESULT_ERROR}
* if intent parameters are specified incorrectly or it will display Toast messages to the user
* if those parameters are specified via the activity UI.
*/
public class AddFileActivity extends Activity {
private static final String TAG = "AutoBackupSample";
/**
* The intent parameter that specifies a file name. The file name must be unique for the
* application internal directory.
*/
public static final String FILE_NAME = "file_name";
/**
* The intent parameter that specifies a file size in bytes. The size must be a number
* larger or equal to 0.
*/
public static final String FILE_SIZE_IN_BYTES = "file_size_in_bytes";
/**
* The file storage is an optional parameter. It should be one of these:
* "INTERNAL", "EXTERNAL", "DONOTBACKUP". The default option is "INTERNAL".
*/
public static final String FILE_STORAGE = "file_storage";
/**
* A file size multiplier. It is used to calculate the total number of bytes to be added
* to the file.
*/
private int mSizeMultiplier = 1;
/**
* Defines File Storage options.
*/
private static enum FileStorage {
INTERNAL,
EXTERNAL,
DONOTBACKUP;
}
/**
* Contains a selected by a user file storage option.
*/
private FileStorage mFileStorage = FileStorage.INTERNAL;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.add_file);
initFileSizeSpinner();
initFileStorageSpinner();
}
@Override
protected void onResume() {
super.onResume();
// If an intent has extra parameters, create the file and finish the activity.
if (getIntent().hasExtra(FILE_NAME) && getIntent().hasExtra(FILE_SIZE_IN_BYTES)) {
String fileName = getIntent().getStringExtra(FILE_NAME);
String sizeInBytesParamValue = getIntent().getStringExtra(FILE_SIZE_IN_BYTES);
String fileStorageParamValue = FileStorage.INTERNAL.toString();
if (getIntent().hasExtra(FILE_STORAGE)) {
fileStorageParamValue = getIntent().getStringExtra(FILE_STORAGE);
}
if (TextUtils.isEmpty(fileName) ||
isFileExists(fileName) ||
!isSizeValid(sizeInBytesParamValue) ||
!isFileStorageParamValid(fileStorageParamValue)) {
setResult(MainActivityFragment.ADD_FILE_RESULT_ERROR);
finish();
return;
}
mFileStorage = FileStorage.valueOf(fileStorageParamValue);
if (mFileStorage == FileStorage.EXTERNAL && !Utils.isExternalStorageAvailable()) {
setResult(MainActivityFragment.ADD_FILE_RESULT_ERROR);
finish();
return;
}
createFileWithRandomDataAndFinishActivity(fileName, mFileStorage,
sizeInBytesParamValue);
}
}
/**
* A handler function for a Create File button click event.
*
* @param view a reference to the Create File button view.
*/
public void onCreateFileButtonClick(View view) {
EditText fileNameEditText = (EditText) findViewById(R.id.file_name);
EditText fileSizeEditText = (EditText) findViewById(R.id.file_size);
String fileName = fileNameEditText.getText().toString();
String fileSizeEditTextValue = fileSizeEditText.getText().toString();
if (TextUtils.isEmpty(fileName) || isFileExists(fileName)) {
Toast toast = Toast.makeText(this, getText(R.string.file_exists), Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
toast.show();
return;
}
if (!isSizeValid(fileSizeEditTextValue)) {
Toast toast = Toast.makeText(this, getText(R.string.file_size_is_invalid),
Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
toast.show();
return;
}
long fileSize = Integer.parseInt(fileSizeEditTextValue) * mSizeMultiplier;
if (mFileStorage == FileStorage.EXTERNAL && !Utils.isExternalStorageAvailable()) {
Toast toast = Toast.makeText(this,
getText(R.string.external_storage_unavailable), Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
toast.show();
return;
}
createFileWithRandomDataAndFinishActivity(fileName, mFileStorage, String.valueOf(fileSize));
}
private void initFileSizeSpinner() {
Spinner spinner = (Spinner) findViewById(R.id.file_size_spinner);
final ArrayAdapter<CharSequence> adapter =
ArrayAdapter.createFromResource(this, R.array.file_size_array,
android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String sizeMeasure = adapter.getItem(position).toString();
mSizeMultiplier = (int) Math.pow(1024, position);
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, String.format("Selected: %s, %d", sizeMeasure,
mSizeMultiplier));
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
private void initFileStorageSpinner() {
Spinner spinner = (Spinner) findViewById(R.id.storage_spinner);
final ArrayAdapter<CharSequence> adapter =
ArrayAdapter.createFromResource(this, R.array.file_storage_array,
android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
mFileStorage = FileStorage.values()[position];
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
private void createFileWithRandomDataAndFinishActivity(String fileName, FileStorage storage,
String sizeInBytes) {
long size = Long.valueOf(sizeInBytes);
File file = null;
FileOutputStream out = null;
BufferedOutputStream bufOut = null;
try {
switch (storage) {
case INTERNAL:
file = getInternalFile(fileName);
out = openFileOutput(file.getName(), Context.MODE_PRIVATE);
break;
case EXTERNAL:
assert Utils.isExternalStorageAvailable() :
"The external storage is not available";
File externalAppDir = getExternalFilesDir(null);
file = new File(externalAppDir, fileName);
out = new FileOutputStream(file);
break;
case DONOTBACKUP:
file = new File(getNoBackupFilesDir(), fileName);
out = new FileOutputStream(file);
break;
}
if (file == null || out == null) {
Log.d(TAG, "Unable to create file output stream");
// Returning back to the caller activity.
setResult(MainActivityFragment.ADD_FILE_RESULT_ERROR);
finish();
return;
}
bufOut = new BufferedOutputStream(out);
for (int i = 0; i < size; i++) {
byte b = (byte) (255 * Math.random());
bufOut.write(b);
}
String message = String.format("File created: %s, size: %s bytes",
file.getAbsolutePath(), sizeInBytes);
Toast toast = Toast.makeText(this, message, Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
toast.show();
Log.d(TAG, message);
// Returning back to the caller activity.
setResult(MainActivityFragment.ADD_FILE_RESULT_SUCCESS);
finish();
} catch (Exception e) {
Log.e(TAG, e.getMessage(), e);
// Returning back to the caller activity.
setResult(MainActivityFragment.ADD_FILE_RESULT_ERROR);
finish();
} finally {
if (bufOut != null) {
try {
bufOut.close();
} catch (Exception e) {
// Ignore.
}
}
}
}
private boolean isFileExists(String fileName) {
File file = getInternalFile(fileName);
if (file.exists()) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "This file exists: " + file.getName());
}
return true;
}
return false;
}
private boolean isSizeValid(String sizeInBytesParamValue) {
long sizeInBytes = 0;
try {
sizeInBytes = Long.valueOf(sizeInBytesParamValue);
} catch (NumberFormatException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Invalid file size: " + sizeInBytesParamValue);
}
return false;
}
// Validate file size value. It should be 0 or a positive number.
if (sizeInBytes < 0) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Invalid file size: " + sizeInBytes);
}
return false;
}
return true;
}
private boolean isFileStorageParamValid(String fileStorage) {
try {
mFileStorage = FileStorage.valueOf(fileStorage);
} catch (IllegalArgumentException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Invalid file storage: " + fileStorage);
}
return false;
}
return true;
}
private File getInternalFile(String fileName) {
File internalAppDir = getFilesDir();
return new File(internalAppDir, fileName);
}
}