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 android.annotation.TargetApi;
20import android.mtp.MtpDeviceInfo;
21import android.net.Uri;
22import android.os.Handler;
23import android.util.Log;
24
25import com.android.gallery3d.R;
26import com.android.gallery3d.app.GalleryApp;
27import com.android.gallery3d.common.ApiHelper;
28import com.android.gallery3d.util.Future;
29import com.android.gallery3d.util.FutureListener;
30import com.android.gallery3d.util.MediaSetUtils;
31import com.android.gallery3d.util.ThreadPool.Job;
32import com.android.gallery3d.util.ThreadPool.JobContext;
33
34import java.util.ArrayList;
35import java.util.Collections;
36import java.util.List;
37
38// MtpDeviceSet -- MtpDevice -- MtpImage
39@TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB_MR1)
40public class MtpDeviceSet extends MediaSet
41        implements FutureListener<ArrayList<MediaSet>> {
42    private static final String TAG = "MtpDeviceSet";
43
44    private GalleryApp mApplication;
45    private final ChangeNotifier mNotifier;
46    private final MtpContext mMtpContext;
47    private final String mName;
48    private final Handler mHandler;
49
50    private Future<ArrayList<MediaSet>> mLoadTask;
51    private ArrayList<MediaSet> mDeviceSet = new ArrayList<MediaSet>();
52    private ArrayList<MediaSet> mLoadBuffer;
53    private boolean mIsLoading;
54
55    public MtpDeviceSet(Path path, GalleryApp application, MtpContext mtpContext) {
56        super(path, nextVersionNumber());
57        mApplication = application;
58        mNotifier = new ChangeNotifier(this, Uri.parse("mtp://"), application);
59        mMtpContext = mtpContext;
60        mName = application.getResources().getString(R.string.set_label_mtp_devices);
61        mHandler = new Handler(mApplication.getMainLooper());
62    }
63
64    private class DevicesLoader implements Job<ArrayList<MediaSet>> {
65        @Override
66        public ArrayList<MediaSet> run(JobContext jc) {
67            DataManager dataManager = mApplication.getDataManager();
68            ArrayList<MediaSet> result = new ArrayList<MediaSet>();
69
70            // Enumerate all devices
71            List<android.mtp.MtpDevice> devices = mMtpContext.getMtpClient().getDeviceList();
72            Log.v(TAG, "loadDevices: " + devices + ", size=" + devices.size());
73            for (android.mtp.MtpDevice mtpDevice : devices) {
74                synchronized (DataManager.LOCK) {
75                    int deviceId = mtpDevice.getDeviceId();
76                    Path childPath = mPath.getChild(deviceId);
77                    MtpDevice device = (MtpDevice) dataManager.peekMediaObject(childPath);
78                    if (device == null) {
79                        device = new MtpDevice(childPath, mApplication, deviceId, mMtpContext);
80                    }
81                    Log.d(TAG, "add device " + device);
82                    result.add(device);
83                }
84            }
85            Collections.sort(result, MediaSetUtils.NAME_COMPARATOR);
86            return result;
87        }
88    }
89
90    public static String getDeviceName(MtpContext mtpContext, int deviceId) {
91        android.mtp.MtpDevice device = mtpContext.getMtpClient().getDevice(deviceId);
92        if (device == null) {
93            return "";
94        }
95        MtpDeviceInfo info = device.getDeviceInfo();
96        if (info == null) {
97            return "";
98        }
99        String manufacturer = info.getManufacturer().trim();
100        String model = info.getModel().trim();
101        return manufacturer + " " + model;
102    }
103
104    @Override
105    public MediaSet getSubMediaSet(int index) {
106        return index < mDeviceSet.size() ? mDeviceSet.get(index) : null;
107    }
108
109    @Override
110    public int getSubMediaSetCount() {
111        return mDeviceSet.size();
112    }
113
114    @Override
115    public String getName() {
116        return mName;
117    }
118
119    @Override
120    public synchronized boolean isLoading() {
121        return mIsLoading;
122    }
123
124    @Override
125    public synchronized long reload() {
126        if (mNotifier.isDirty()) {
127            if (mLoadTask != null) mLoadTask.cancel();
128            mIsLoading = true;
129            mLoadTask = mApplication.getThreadPool().submit(new DevicesLoader(), this);
130        }
131        if (mLoadBuffer != null) {
132            mDeviceSet = mLoadBuffer;
133            mLoadBuffer = null;
134            for (MediaSet device : mDeviceSet) {
135                device.reload();
136            }
137            mDataVersion = nextVersionNumber();
138        }
139        return mDataVersion;
140    }
141
142    @Override
143    public synchronized void onFutureDone(Future<ArrayList<MediaSet>> future) {
144        if (future != mLoadTask) return;
145        mLoadBuffer = future.get();
146        mIsLoading = false;
147        if (mLoadBuffer == null) mLoadBuffer = new ArrayList<MediaSet>();
148
149        mHandler.post(new Runnable() {
150            @Override
151            public void run() {
152                notifyContentChanged();
153            }
154        });
155    }
156}
157