1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.example.android.autobackupsample; 18 19 import android.app.Activity; 20 import android.content.Context; 21 import android.os.Bundle; 22 import android.text.TextUtils; 23 import android.util.Log; 24 import android.view.Gravity; 25 import android.view.View; 26 import android.widget.AdapterView; 27 import android.widget.ArrayAdapter; 28 import android.widget.EditText; 29 import android.widget.Spinner; 30 import android.widget.Toast; 31 32 import com.example.android.autobackupsample.MainActivityFragment; 33 34 import java.io.BufferedOutputStream; 35 import java.io.File; 36 import java.io.FileOutputStream; 37 38 /** 39 * The purpose of AddFileActivity activity is to create a data file based on the 40 * file name and size parameters specified as an Intent external parameters or with the 41 * activity UI. 42 * <p/> 43 * The optional intent parameters are 44 * {@link com.example.android.autobackupsample.AddFileActivity#FILE_NAME} and 45 * {@link com.example.android.autobackupsample.AddFileActivity#FILE_SIZE_IN_BYTES}. 46 * {@link com.example.android.autobackupsample.AddFileActivity#FILE_STORAGE}. 47 * <p/> 48 * The activity will return an 49 * {@link com.example.android.autobackupsample.MainActivityFragment#ADD_FILE_RESULT_ERROR} 50 * if intent parameters are specified incorrectly or it will display Toast messages to the user 51 * if those parameters are specified via the activity UI. 52 */ 53 public class AddFileActivity extends Activity { 54 55 private static final String TAG = "AutoBackupSample"; 56 57 /** 58 * The intent parameter that specifies a file name. The file name must be unique for the 59 * application internal directory. 60 */ 61 public static final String FILE_NAME = "file_name"; 62 63 /** 64 * The intent parameter that specifies a file size in bytes. The size must be a number 65 * larger or equal to 0. 66 */ 67 public static final String FILE_SIZE_IN_BYTES = "file_size_in_bytes"; 68 69 /** 70 * The file storage is an optional parameter. It should be one of these: 71 * "INTERNAL", "EXTERNAL", "DONOTBACKUP". The default option is "INTERNAL". 72 */ 73 public static final String FILE_STORAGE = "file_storage"; 74 75 /** 76 * A file size multiplier. It is used to calculate the total number of bytes to be added 77 * to the file. 78 */ 79 private int mSizeMultiplier = 1; 80 81 /** 82 * Defines File Storage options. 83 */ 84 private static enum FileStorage { 85 INTERNAL, 86 EXTERNAL, 87 DONOTBACKUP; 88 } 89 90 /** 91 * Contains a selected by a user file storage option. 92 */ 93 private FileStorage mFileStorage = FileStorage.INTERNAL; 94 95 @Override onCreate(Bundle savedInstanceState)96 public void onCreate(Bundle savedInstanceState) { 97 super.onCreate(savedInstanceState); 98 setContentView(R.layout.add_file); 99 initFileSizeSpinner(); 100 initFileStorageSpinner(); 101 } 102 103 @Override onResume()104 protected void onResume() { 105 super.onResume(); 106 // If an intent has extra parameters, create the file and finish the activity. 107 if (getIntent().hasExtra(FILE_NAME) && getIntent().hasExtra(FILE_SIZE_IN_BYTES)) { 108 String fileName = getIntent().getStringExtra(FILE_NAME); 109 String sizeInBytesParamValue = getIntent().getStringExtra(FILE_SIZE_IN_BYTES); 110 String fileStorageParamValue = FileStorage.INTERNAL.toString(); 111 112 if (getIntent().hasExtra(FILE_STORAGE)) { 113 fileStorageParamValue = getIntent().getStringExtra(FILE_STORAGE); 114 } 115 116 if (TextUtils.isEmpty(fileName) || 117 isFileExists(fileName) || 118 !isSizeValid(sizeInBytesParamValue) || 119 !isFileStorageParamValid(fileStorageParamValue)) { 120 setResult(MainActivityFragment.ADD_FILE_RESULT_ERROR); 121 finish(); 122 return; 123 } 124 125 mFileStorage = FileStorage.valueOf(fileStorageParamValue); 126 127 if (mFileStorage == FileStorage.EXTERNAL && !Utils.isExternalStorageAvailable()) { 128 setResult(MainActivityFragment.ADD_FILE_RESULT_ERROR); 129 finish(); 130 return; 131 } 132 133 createFileWithRandomDataAndFinishActivity(fileName, mFileStorage, 134 sizeInBytesParamValue); 135 } 136 } 137 138 /** 139 * A handler function for a Create File button click event. 140 * 141 * @param view a reference to the Create File button view. 142 */ onCreateFileButtonClick(View view)143 public void onCreateFileButtonClick(View view) { 144 EditText fileNameEditText = (EditText) findViewById(R.id.file_name); 145 EditText fileSizeEditText = (EditText) findViewById(R.id.file_size); 146 String fileName = fileNameEditText.getText().toString(); 147 String fileSizeEditTextValue = fileSizeEditText.getText().toString(); 148 149 if (TextUtils.isEmpty(fileName) || isFileExists(fileName)) { 150 Toast toast = Toast.makeText(this, getText(R.string.file_exists), Toast.LENGTH_LONG); 151 toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0); 152 toast.show(); 153 return; 154 } 155 156 if (!isSizeValid(fileSizeEditTextValue)) { 157 Toast toast = Toast.makeText(this, getText(R.string.file_size_is_invalid), 158 Toast.LENGTH_LONG); 159 toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0); 160 toast.show(); 161 return; 162 } 163 164 long fileSize = Integer.parseInt(fileSizeEditTextValue) * mSizeMultiplier; 165 166 if (mFileStorage == FileStorage.EXTERNAL && !Utils.isExternalStorageAvailable()) { 167 Toast toast = Toast.makeText(this, 168 getText(R.string.external_storage_unavailable), Toast.LENGTH_LONG); 169 toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0); 170 toast.show(); 171 return; 172 } 173 174 createFileWithRandomDataAndFinishActivity(fileName, mFileStorage, String.valueOf(fileSize)); 175 } 176 initFileSizeSpinner()177 private void initFileSizeSpinner() { 178 Spinner spinner = (Spinner) findViewById(R.id.file_size_spinner); 179 final ArrayAdapter<CharSequence> adapter = 180 ArrayAdapter.createFromResource(this, R.array.file_size_array, 181 android.R.layout.simple_spinner_item); 182 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 183 spinner.setAdapter(adapter); 184 spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { 185 @Override 186 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { 187 String sizeMeasure = adapter.getItem(position).toString(); 188 mSizeMultiplier = (int) Math.pow(1024, position); 189 if (Log.isLoggable(TAG, Log.DEBUG)) { 190 Log.d(TAG, String.format("Selected: %s, %d", sizeMeasure, 191 mSizeMultiplier)); 192 } 193 } 194 195 @Override 196 public void onNothingSelected(AdapterView<?> parent) { 197 198 } 199 }); 200 } 201 initFileStorageSpinner()202 private void initFileStorageSpinner() { 203 Spinner spinner = (Spinner) findViewById(R.id.storage_spinner); 204 final ArrayAdapter<CharSequence> adapter = 205 ArrayAdapter.createFromResource(this, R.array.file_storage_array, 206 android.R.layout.simple_spinner_item); 207 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 208 spinner.setAdapter(adapter); 209 spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { 210 @Override 211 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { 212 mFileStorage = FileStorage.values()[position]; 213 } 214 215 @Override 216 public void onNothingSelected(AdapterView<?> parent) { 217 218 } 219 }); 220 } 221 createFileWithRandomDataAndFinishActivity(String fileName, FileStorage storage, String sizeInBytes)222 private void createFileWithRandomDataAndFinishActivity(String fileName, FileStorage storage, 223 String sizeInBytes) { 224 long size = Long.valueOf(sizeInBytes); 225 File file = null; 226 FileOutputStream out = null; 227 BufferedOutputStream bufOut = null; 228 try { 229 switch (storage) { 230 case INTERNAL: 231 file = getInternalFile(fileName); 232 out = openFileOutput(file.getName(), Context.MODE_PRIVATE); 233 break; 234 case EXTERNAL: 235 assert Utils.isExternalStorageAvailable() : 236 "The external storage is not available"; 237 File externalAppDir = getExternalFilesDir(null); 238 file = new File(externalAppDir, fileName); 239 out = new FileOutputStream(file); 240 break; 241 case DONOTBACKUP: 242 file = new File(getNoBackupFilesDir(), fileName); 243 out = new FileOutputStream(file); 244 break; 245 } 246 247 if (file == null || out == null) { 248 Log.d(TAG, "Unable to create file output stream"); 249 // Returning back to the caller activity. 250 setResult(MainActivityFragment.ADD_FILE_RESULT_ERROR); 251 finish(); 252 return; 253 } 254 255 bufOut = new BufferedOutputStream(out); 256 for (int i = 0; i < size; i++) { 257 byte b = (byte) (255 * Math.random()); 258 bufOut.write(b); 259 } 260 261 String message = String.format("File created: %s, size: %s bytes", 262 file.getAbsolutePath(), sizeInBytes); 263 264 Toast toast = Toast.makeText(this, message, Toast.LENGTH_LONG); 265 toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0); 266 toast.show(); 267 Log.d(TAG, message); 268 269 // Returning back to the caller activity. 270 setResult(MainActivityFragment.ADD_FILE_RESULT_SUCCESS); 271 finish(); 272 } catch (Exception e) { 273 Log.e(TAG, e.getMessage(), e); 274 // Returning back to the caller activity. 275 setResult(MainActivityFragment.ADD_FILE_RESULT_ERROR); 276 finish(); 277 } finally { 278 if (bufOut != null) { 279 try { 280 bufOut.close(); 281 } catch (Exception e) { 282 // Ignore. 283 } 284 } 285 } 286 } 287 isFileExists(String fileName)288 private boolean isFileExists(String fileName) { 289 File file = getInternalFile(fileName); 290 if (file.exists()) { 291 if (Log.isLoggable(TAG, Log.DEBUG)) { 292 Log.d(TAG, "This file exists: " + file.getName()); 293 } 294 return true; 295 } 296 return false; 297 } 298 isSizeValid(String sizeInBytesParamValue)299 private boolean isSizeValid(String sizeInBytesParamValue) { 300 long sizeInBytes = 0; 301 try { 302 sizeInBytes = Long.valueOf(sizeInBytesParamValue); 303 } catch (NumberFormatException e) { 304 if (Log.isLoggable(TAG, Log.DEBUG)) { 305 Log.d(TAG, "Invalid file size: " + sizeInBytesParamValue); 306 } 307 return false; 308 } 309 310 // Validate file size value. It should be 0 or a positive number. 311 if (sizeInBytes < 0) { 312 if (Log.isLoggable(TAG, Log.DEBUG)) { 313 Log.d(TAG, "Invalid file size: " + sizeInBytes); 314 } 315 return false; 316 } 317 return true; 318 } 319 isFileStorageParamValid(String fileStorage)320 private boolean isFileStorageParamValid(String fileStorage) { 321 try { 322 mFileStorage = FileStorage.valueOf(fileStorage); 323 } catch (IllegalArgumentException e) { 324 if (Log.isLoggable(TAG, Log.DEBUG)) { 325 Log.d(TAG, "Invalid file storage: " + fileStorage); 326 } 327 return false; 328 } 329 return true; 330 } 331 getInternalFile(String fileName)332 private File getInternalFile(String fileName) { 333 File internalAppDir = getFilesDir(); 334 return new File(internalAppDir, fileName); 335 } 336 337 }