OSDN Git Service

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