1f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu/* 2f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu * Copyright (C) 2013 The Android Open Source Project 3f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu * 4f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu * Licensed under the Apache License, Version 2.0 (the "License"); 5f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu * you may not use this file except in compliance with the License. 6f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu * You may obtain a copy of the License at 7f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu * 8f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu * http://www.apache.org/licenses/LICENSE-2.0 9f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu * 10f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu * Unless required by applicable law or agreed to in writing, software 11f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu * distributed under the License is distributed on an "AS IS" BASIS, 12f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu * See the License for the specific language governing permissions and 14f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu * limitations under the License. 15f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu */ 16f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu 17f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescupackage com.android.gallery3d.ingest.data; 18f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu 19f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport android.annotation.TargetApi; 20f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport android.content.Context; 21f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport android.mtp.MtpDevice; 22f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport android.os.Build; 23f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport android.os.Environment; 24f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport android.os.PowerManager; 25f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport android.os.StatFs; 26f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport android.util.Log; 27f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu 28f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport java.io.File; 29f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport java.util.Collection; 30f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport java.util.LinkedList; 31f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport java.util.List; 32f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu 33f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu/** 34f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu * Task that handles the copying of items from an MTP device. 35f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu */ 36f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1) 37f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescupublic class ImportTask implements Runnable { 38f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu 39f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu private static final String TAG = "ImportTask"; 40f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu 41f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu /** 42f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu * Import progress listener. 43f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu */ 44f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu public interface Listener { 45f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu void onImportProgress(int visitedCount, int totalCount, String pathIfSuccessful); 46f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu 47f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu void onImportFinish(Collection<IngestObjectInfo> objectsNotImported, int visitedCount); 48f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu } 49f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu 50f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu private static final String WAKELOCK_LABEL = "Google Photos MTP Import Task"; 51f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu 52f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu private Listener mListener; 53f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu private String mDestAlbumName; 54f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu private Collection<IngestObjectInfo> mObjectsToImport; 55f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu private MtpDevice mDevice; 56f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu private PowerManager.WakeLock mWakeLock; 57f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu 58f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu public ImportTask(MtpDevice device, Collection<IngestObjectInfo> objectsToImport, 59f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu String destAlbumName, Context context) { 60f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu mDestAlbumName = destAlbumName; 61f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu mObjectsToImport = objectsToImport; 62f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu mDevice = device; 63f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); 64f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu mWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, WAKELOCK_LABEL); 65f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu } 66f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu 67f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu public void setListener(Listener listener) { 68f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu mListener = listener; 69f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu } 70f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu 71f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu @Override 72f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu public void run() { 73f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu mWakeLock.acquire(); 74f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu try { 75f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu List<IngestObjectInfo> objectsNotImported = new LinkedList<IngestObjectInfo>(); 76f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu int visited = 0; 77f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu int total = mObjectsToImport.size(); 78f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu mListener.onImportProgress(visited, total, null); 79f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu File dest = new File(Environment.getExternalStorageDirectory(), mDestAlbumName); 80f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu dest.mkdirs(); 81f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu for (IngestObjectInfo object : mObjectsToImport) { 82f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu visited++; 83f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu String importedPath = null; 84f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu if (hasSpaceForSize(object.getCompressedSize())) { 85f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu importedPath = new File(dest, object.getName(mDevice)).getAbsolutePath(); 86f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu if (!mDevice.importFile(object.getObjectHandle(), importedPath)) { 87f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu importedPath = null; 88f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu } 89f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu } 90f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu if (importedPath == null) { 91f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu objectsNotImported.add(object); 92f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu } 93f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu if (mListener != null) { 94f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu mListener.onImportProgress(visited, total, importedPath); 95f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu } 96f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu } 97f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu if (mListener != null) { 98f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu mListener.onImportFinish(objectsNotImported, visited); 99f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu } 100f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu } finally { 101f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu mListener = null; 102f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu mWakeLock.release(); 103f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu } 104f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu } 105f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu 106f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu private static boolean hasSpaceForSize(long size) { 107f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu String state = Environment.getExternalStorageState(); 108f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu if (!Environment.MEDIA_MOUNTED.equals(state)) { 109f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu return false; 110f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu } 111f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu 112f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu String path = Environment.getExternalStorageDirectory().getPath(); 113f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu try { 114f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu StatFs stat = new StatFs(path); 115f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu return stat.getAvailableBlocks() * (long) stat.getBlockSize() > size; 116f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu } catch (Exception e) { 117f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu Log.i(TAG, "Fail to access external storage", e); 118f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu } 119f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu return false; 120f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu } 121f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu} 122