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