OSDN Git Service

Merge "Import translations. DO NOT MERGE"
[android-x86/packages-apps-Gallery2.git] / src / com / android / gallery3d / ingest / IngestService.java
1 /*
2  * Copyright (C) 2013 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.android.gallery3d.ingest;
18
19 import android.app.NotificationManager;
20 import android.app.PendingIntent;
21 import android.app.Service;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.media.MediaScannerConnection;
25 import android.media.MediaScannerConnection.MediaScannerConnectionClient;
26 import android.mtp.MtpDevice;
27 import android.mtp.MtpDeviceInfo;
28 import android.mtp.MtpObjectInfo;
29 import android.net.Uri;
30 import android.os.Binder;
31 import android.os.IBinder;
32 import android.os.SystemClock;
33 import android.support.v4.app.NotificationCompat;
34 import android.util.SparseBooleanArray;
35 import android.widget.Adapter;
36
37 import com.android.gallery3d.R;
38 import com.android.gallery3d.app.NotificationIds;
39 import com.android.gallery3d.data.MtpClient;
40 import com.android.gallery3d.ingest.ui.MtpBitmapCache;
41 import com.android.gallery3d.util.BucketNames;
42
43 import java.util.ArrayList;
44 import java.util.Collection;
45 import java.util.List;
46
47 public class IngestService extends Service implements ImportTask.Listener,
48         MtpDeviceIndex.ProgressListener, MtpClient.Listener {
49
50     public class LocalBinder extends Binder {
51         IngestService getService() {
52             return IngestService.this;
53         }
54     }
55
56     private static final int PROGRESS_UPDATE_INTERVAL_MS = 180;
57
58     private static MtpClient sClient;
59
60     private final IBinder mBinder = new LocalBinder();
61     private ScannerClient mScannerClient;
62     private MtpDevice mDevice;
63     private String mDevicePrettyName;
64     private MtpDeviceIndex mIndex;
65     private IngestActivity mClientActivity;
66     private boolean mRedeliverImportFinish = false;
67     private Collection<MtpObjectInfo> mRedeliverObjectsNotImported;
68     private boolean mRedeliverNotifyIndexChanged = false;
69     private NotificationManager mNotificationManager;
70     private NotificationCompat.Builder mNotificationBuilder;
71     private long mLastProgressIndexTime = 0;
72
73     @Override
74     public void onCreate() {
75         super.onCreate();
76         mScannerClient = new ScannerClient(this);
77         mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
78         mNotificationBuilder = new NotificationCompat.Builder(this);
79         mNotificationBuilder.setSmallIcon(android.R.drawable.stat_notify_sync) // TODO drawable
80                 .setContentIntent(PendingIntent.getActivity(this, 0, new Intent(this, IngestActivity.class), 0));
81         mIndex = MtpDeviceIndex.getInstance();
82         mIndex.setProgressListener(this);
83
84         if (sClient == null) {
85             sClient = new MtpClient(getApplicationContext());
86         }
87         List<MtpDevice> devices = sClient.getDeviceList();
88         if (devices.size() > 0) {
89             setDevice(devices.get(0));
90         }
91         sClient.addListener(this);
92     }
93
94     @Override
95     public void onDestroy() {
96         sClient.removeListener(this);
97         mIndex.unsetProgressListener(this);
98         super.onDestroy();
99     }
100
101     @Override
102     public IBinder onBind(Intent intent) {
103         return mBinder;
104     }
105
106     private void setDevice(MtpDevice device) {
107         if (mDevice == device) return;
108         mRedeliverImportFinish = false;
109         mRedeliverObjectsNotImported = null;
110         mRedeliverNotifyIndexChanged = false;
111         mDevice = device;
112         mIndex.setDevice(mDevice);
113         if (mDevice != null) {
114             MtpDeviceInfo deviceInfo = mDevice.getDeviceInfo();
115             mDevicePrettyName = deviceInfo.getModel();
116             mNotificationBuilder.setContentTitle(mDevicePrettyName);
117             new Thread(mIndex.getIndexRunnable()).start();
118         } else {
119             mDevicePrettyName = null;
120         }
121         if (mClientActivity != null) {
122             mClientActivity.notifyIndexChanged();
123         } else {
124             mRedeliverNotifyIndexChanged = true;
125         }
126     }
127
128     protected MtpDeviceIndex getIndex() {
129         return mIndex;
130     }
131
132     protected void setClientActivity(IngestActivity activity) {
133         if (mClientActivity == activity) return;
134         mClientActivity = activity;
135         if (mClientActivity == null) return;
136         mNotificationManager.cancel(NotificationIds.INGEST_NOTIFICATION_IMPORTING);
137         mNotificationManager.cancel(NotificationIds.INGEST_NOTIFICATION_SCANNING);
138         if (mRedeliverImportFinish) {
139             mClientActivity.onImportFinish(mRedeliverObjectsNotImported);
140             mRedeliverImportFinish = false;
141             mRedeliverObjectsNotImported = null;
142         }
143         if (mRedeliverNotifyIndexChanged) {
144             mClientActivity.notifyIndexChanged();
145             mRedeliverNotifyIndexChanged = false;
146         }
147     }
148
149     protected void importSelectedItems(SparseBooleanArray selected, Adapter adapter) {
150         List<MtpObjectInfo> importHandles = new ArrayList<MtpObjectInfo>();
151         for (int i = 0; i < selected.size(); i++) {
152             if (selected.valueAt(i)) {
153                 Object item = adapter.getItem(selected.keyAt(i));
154                 if (item instanceof MtpObjectInfo) {
155                     importHandles.add(((MtpObjectInfo) item));
156                 }
157             }
158         }
159         ImportTask task = new ImportTask(mDevice, importHandles, BucketNames.IMPORTED, this);
160         task.setListener(this);
161         mNotificationBuilder.setProgress(0, 0, true)
162             .setContentText(getResources().getText(R.string.ingest_importing));
163         startForeground(NotificationIds.INGEST_NOTIFICATION_IMPORTING,
164                     mNotificationBuilder.build());
165         new Thread(task).start();
166     }
167
168     @Override
169     public void deviceAdded(MtpDevice device) {
170         if (mDevice == null) {
171             setDevice(device);
172         }
173     }
174
175     @Override
176     public void deviceRemoved(MtpDevice device) {
177         if (device == mDevice) {
178             setDevice(null);
179         }
180         MtpBitmapCache.onDeviceDisconnected(device);
181     }
182
183     @Override
184     public void onImportProgress(int visitedCount, int totalCount,
185             String pathIfSuccessful) {
186         if (pathIfSuccessful != null) {
187             mScannerClient.scanPath(pathIfSuccessful);
188         }
189         if (mClientActivity != null) {
190             mClientActivity.onImportProgress(visitedCount, totalCount, pathIfSuccessful);
191         }
192         mNotificationBuilder.setProgress(totalCount, visitedCount, false)
193             .setContentText(getResources().getText(R.string.ingest_importing));
194         mNotificationManager.notify(NotificationIds.INGEST_NOTIFICATION_IMPORTING,
195                 mNotificationBuilder.build());
196     }
197
198     @Override
199     public void onImportFinish(Collection<MtpObjectInfo> objectsNotImported) {
200         if (mClientActivity != null) {
201             mClientActivity.onImportFinish(objectsNotImported);
202         } else {
203             mRedeliverImportFinish = true;
204             mRedeliverObjectsNotImported = objectsNotImported;
205             mNotificationBuilder.setProgress(0, 0, false)
206                 .setContentText(getResources().getText(R.string.import_complete));
207             mNotificationManager.notify(NotificationIds.INGEST_NOTIFICATION_IMPORTING,
208                     mNotificationBuilder.build());
209         }
210         stopForeground(mClientActivity != null);
211     }
212
213     @Override
214     public void onObjectIndexed(MtpObjectInfo object, int numVisited) {
215         if (mClientActivity != null) {
216             mClientActivity.onObjectIndexed(object, numVisited);
217         } else {
218             // Throttle the updates to one every PROGRESS_UPDATE_INTERVAL_MS milliseconds
219             long currentTime = SystemClock.uptimeMillis();
220             if (currentTime > mLastProgressIndexTime + PROGRESS_UPDATE_INTERVAL_MS) {
221                 mLastProgressIndexTime = currentTime;
222                 mNotificationBuilder.setProgress(0, numVisited, true)
223                         .setContentText(getResources().getText(R.string.ingest_scanning));
224                 mNotificationManager.notify(NotificationIds.INGEST_NOTIFICATION_SCANNING,
225                         mNotificationBuilder.build());
226             }
227         }
228     }
229
230     @Override
231     public void onSorting() {
232         if (mClientActivity != null) mClientActivity.onSorting();
233     }
234
235     @Override
236     public void onIndexFinish() {
237         if (mClientActivity != null) {
238             mClientActivity.onIndexFinish();
239         } else {
240             mNotificationBuilder.setProgress(0, 0, false)
241                 .setContentText(getResources().getText(R.string.ingest_scanning_done));
242             mNotificationManager.notify(NotificationIds.INGEST_NOTIFICATION_SCANNING,
243                     mNotificationBuilder.build());
244         }
245     }
246
247     // Copied from old Gallery3d code
248     private static final class ScannerClient implements MediaScannerConnectionClient {
249         ArrayList<String> mPaths = new ArrayList<String>();
250         MediaScannerConnection mScannerConnection;
251         boolean mConnected;
252         Object mLock = new Object();
253
254         public ScannerClient(Context context) {
255             mScannerConnection = new MediaScannerConnection(context, this);
256         }
257
258         public void scanPath(String path) {
259             synchronized (mLock) {
260                 if (mConnected) {
261                     mScannerConnection.scanFile(path, null);
262                 } else {
263                     mPaths.add(path);
264                     mScannerConnection.connect();
265                 }
266             }
267         }
268
269         @Override
270         public void onMediaScannerConnected() {
271             synchronized (mLock) {
272                 mConnected = true;
273                 if (!mPaths.isEmpty()) {
274                     for (String path : mPaths) {
275                         mScannerConnection.scanFile(path, null);
276                     }
277                     mPaths.clear();
278                 }
279             }
280         }
281
282         @Override
283         public void onScanCompleted(String path, Uri uri) {
284         }
285     }
286 }