IngestService.java revision 13fec90b6a03e21a88cb8b8425e65289904d4186
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 17package com.android.gallery3d.ingest; 18 19import android.app.NotificationManager; 20import android.app.PendingIntent; 21import android.app.Service; 22import android.content.Context; 23import android.content.Intent; 24import android.media.MediaScannerConnection; 25import android.media.MediaScannerConnection.MediaScannerConnectionClient; 26import android.mtp.MtpDevice; 27import android.mtp.MtpDeviceInfo; 28import android.mtp.MtpObjectInfo; 29import android.net.Uri; 30import android.os.Binder; 31import android.os.IBinder; 32import android.os.SystemClock; 33import android.support.v4.app.NotificationCompat; 34import android.util.SparseBooleanArray; 35import android.widget.Adapter; 36 37import com.android.gallery3d.R; 38import com.android.gallery3d.app.NotificationIds; 39import com.android.gallery3d.data.MtpClient; 40import com.android.gallery3d.util.BucketNames; 41 42import java.util.ArrayList; 43import java.util.Collection; 44import java.util.List; 45 46public 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 } 200 } 201 202 @Override 203 public void onImportProgress(int visitedCount, int totalCount, 204 String pathIfSuccessful) { 205 if (pathIfSuccessful != null) { 206 mScannerClient.scanPath(pathIfSuccessful); 207 } 208 mNeedRelaunchNotification = false; 209 if (mClientActivity != null) { 210 mClientActivity.onImportProgress(visitedCount, totalCount, pathIfSuccessful); 211 } 212 mNotificationBuilder.setProgress(totalCount, visitedCount, false) 213 .setContentText(getResources().getText(R.string.ingest_importing)); 214 mNotificationManager.notify(NotificationIds.INGEST_NOTIFICATION_IMPORTING, 215 mNotificationBuilder.build()); 216 } 217 218 @Override 219 public void onImportFinish(Collection<MtpObjectInfo> objectsNotImported) { 220 stopForeground(true); 221 mNeedRelaunchNotification = true; 222 if (mClientActivity != null) { 223 mClientActivity.onImportFinish(objectsNotImported); 224 } else { 225 mRedeliverImportFinish = true; 226 mRedeliverObjectsNotImported = objectsNotImported; 227 mNotificationBuilder.setProgress(0, 0, false) 228 .setContentText(getResources().getText(R.string.import_complete)); 229 mNotificationManager.notify(NotificationIds.INGEST_NOTIFICATION_IMPORTING, 230 mNotificationBuilder.build()); 231 } 232 } 233 234 @Override 235 public void onObjectIndexed(MtpObjectInfo object, int numVisited) { 236 mNeedRelaunchNotification = false; 237 if (mClientActivity != null) { 238 mClientActivity.onObjectIndexed(object, numVisited); 239 } else { 240 // Throttle the updates to one every PROGRESS_UPDATE_INTERVAL_MS milliseconds 241 long currentTime = SystemClock.uptimeMillis(); 242 if (currentTime > mLastProgressIndexTime + PROGRESS_UPDATE_INTERVAL_MS) { 243 mLastProgressIndexTime = currentTime; 244 mNotificationBuilder.setProgress(0, numVisited, true) 245 .setContentText(getResources().getText(R.string.ingest_scanning)); 246 mNotificationManager.notify(NotificationIds.INGEST_NOTIFICATION_SCANNING, 247 mNotificationBuilder.build()); 248 } 249 } 250 } 251 252 @Override 253 public void onSorting() { 254 if (mClientActivity != null) mClientActivity.onSorting(); 255 } 256 257 @Override 258 public void onIndexFinish() { 259 mNeedRelaunchNotification = true; 260 if (mClientActivity != null) { 261 mClientActivity.onIndexFinish(); 262 } else { 263 mNotificationBuilder.setProgress(0, 0, false) 264 .setContentText(getResources().getText(R.string.ingest_scanning_done)); 265 mNotificationManager.notify(NotificationIds.INGEST_NOTIFICATION_SCANNING, 266 mNotificationBuilder.build()); 267 mRedeliverIndexFinish = true; 268 } 269 } 270 271 // Copied from old Gallery3d code 272 private static final class ScannerClient implements MediaScannerConnectionClient { 273 ArrayList<String> mPaths = new ArrayList<String>(); 274 MediaScannerConnection mScannerConnection; 275 boolean mConnected; 276 Object mLock = new Object(); 277 278 public ScannerClient(Context context) { 279 mScannerConnection = new MediaScannerConnection(context, this); 280 } 281 282 public void scanPath(String path) { 283 synchronized (mLock) { 284 if (mConnected) { 285 mScannerConnection.scanFile(path, null); 286 } else { 287 mPaths.add(path); 288 mScannerConnection.connect(); 289 } 290 } 291 } 292 293 @Override 294 public void onMediaScannerConnected() { 295 synchronized (mLock) { 296 mConnected = true; 297 if (!mPaths.isEmpty()) { 298 for (String path : mPaths) { 299 mScannerConnection.scanFile(path, null); 300 } 301 mPaths.clear(); 302 } 303 } 304 } 305 306 @Override 307 public void onScanCompleted(String path, Uri uri) { 308 } 309 } 310} 311