OSDN Git Service

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