1/*
2 * Copyright (C) 2010 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
17package com.android.gallery3d.data;
18
19import com.android.gallery3d.app.GalleryApp;
20
21import android.hardware.usb.UsbDevice;
22import android.mtp.MtpConstants;
23import android.mtp.MtpObjectInfo;
24import android.mtp.MtpStorageInfo;
25import android.net.Uri;
26import android.util.Log;
27
28import java.util.ArrayList;
29import java.util.List;
30
31public class MtpDevice extends MediaSet {
32    private static final String TAG = "MtpDevice";
33
34    private final GalleryApp mApplication;
35    private final int mDeviceId;
36    private final String mDeviceName;
37    private final DataManager mDataManager;
38    private final MtpContext mMtpContext;
39    private final String mName;
40    private final ChangeNotifier mNotifier;
41    private final Path mItemPath;
42    private List<MtpObjectInfo> mJpegChildren;
43
44    public MtpDevice(Path path, GalleryApp application, int deviceId,
45            String name, MtpContext mtpContext) {
46        super(path, nextVersionNumber());
47        mApplication = application;
48        mDeviceId = deviceId;
49        mDeviceName = UsbDevice.getDeviceName(deviceId);
50        mDataManager = application.getDataManager();
51        mMtpContext = mtpContext;
52        mName = name;
53        mNotifier = new ChangeNotifier(this, Uri.parse("mtp://"), application);
54        mItemPath = Path.fromString("/mtp/item/" + String.valueOf(deviceId));
55        mJpegChildren = new ArrayList<MtpObjectInfo>();
56    }
57
58    public MtpDevice(Path path, GalleryApp application, int deviceId,
59            MtpContext mtpContext) {
60        this(path, application, deviceId,
61                MtpDeviceSet.getDeviceName(mtpContext, deviceId), mtpContext);
62    }
63
64    private List<MtpObjectInfo> loadItems() {
65        ArrayList<MtpObjectInfo> result = new ArrayList<MtpObjectInfo>();
66
67        List<MtpStorageInfo> storageList = mMtpContext.getMtpClient()
68                 .getStorageList(mDeviceName);
69        if (storageList == null) return result;
70
71        for (MtpStorageInfo info : storageList) {
72            collectJpegChildren(info.getStorageId(), 0, result);
73        }
74
75        return result;
76    }
77
78    private void collectJpegChildren(int storageId, int objectId,
79            ArrayList<MtpObjectInfo> result) {
80        ArrayList<MtpObjectInfo> dirChildren = new ArrayList<MtpObjectInfo>();
81
82        queryChildren(storageId, objectId, result, dirChildren);
83
84        for (int i = 0, n = dirChildren.size(); i < n; i++) {
85            MtpObjectInfo info = dirChildren.get(i);
86            collectJpegChildren(storageId, info.getObjectHandle(), result);
87        }
88    }
89
90    private void queryChildren(int storageId, int objectId,
91            ArrayList<MtpObjectInfo> jpeg, ArrayList<MtpObjectInfo> dir) {
92        List<MtpObjectInfo> children = mMtpContext.getMtpClient().getObjectList(
93                mDeviceName, storageId, objectId);
94        if (children == null) return;
95
96        for (MtpObjectInfo obj : children) {
97            int format = obj.getFormat();
98            switch (format) {
99                case MtpConstants.FORMAT_JFIF:
100                case MtpConstants.FORMAT_EXIF_JPEG:
101                    jpeg.add(obj);
102                    break;
103                case MtpConstants.FORMAT_ASSOCIATION:
104                    dir.add(obj);
105                    break;
106                default:
107                    Log.w(TAG, "other type: name = " + obj.getName()
108                            + ", format = " + format);
109            }
110        }
111    }
112
113    public static MtpObjectInfo getObjectInfo(MtpContext mtpContext, int deviceId,
114            int objectId) {
115        String deviceName = UsbDevice.getDeviceName(deviceId);
116        return mtpContext.getMtpClient().getObjectInfo(deviceName, objectId);
117    }
118
119    @Override
120    public ArrayList<MediaItem> getMediaItem(int start, int count) {
121        ArrayList<MediaItem> result = new ArrayList<MediaItem>();
122        int begin = start;
123        int end = Math.min(start + count, mJpegChildren.size());
124
125        DataManager dataManager = mApplication.getDataManager();
126        for (int i = begin; i < end; i++) {
127            MtpObjectInfo child = mJpegChildren.get(i);
128            Path childPath = mItemPath.getChild(child.getObjectHandle());
129            MtpImage image = (MtpImage) dataManager.peekMediaObject(childPath);
130            if (image == null) {
131                image = new MtpImage(
132                        childPath, mApplication, mDeviceId, child, mMtpContext);
133            } else {
134                image.updateContent(child);
135            }
136            result.add(image);
137        }
138        return result;
139    }
140
141    @Override
142    public int getMediaItemCount() {
143        return mJpegChildren.size();
144    }
145
146    @Override
147    public String getName() {
148        return mName;
149    }
150
151    @Override
152    public long reload() {
153        if (mNotifier.isDirty()) {
154            mDataVersion = nextVersionNumber();
155            mJpegChildren = loadItems();
156        }
157        return mDataVersion;
158    }
159
160    @Override
161    public int getSupportedOperations() {
162        return SUPPORT_IMPORT;
163    }
164
165    @Override
166    public boolean Import() {
167        return mMtpContext.copyAlbum(mDeviceName, mName, mJpegChildren);
168    }
169
170    @Override
171    public boolean isLeafAlbum() {
172        return true;
173    }
174}
175