| /* |
| * Copyright (C) 2013 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.gallery3d.ingest; |
| |
| import android.app.NotificationManager; |
| import android.app.PendingIntent; |
| import android.app.Service; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.media.MediaScannerConnection; |
| import android.media.MediaScannerConnection.MediaScannerConnectionClient; |
| import android.mtp.MtpDevice; |
| import android.mtp.MtpDeviceInfo; |
| import android.mtp.MtpObjectInfo; |
| import android.net.Uri; |
| import android.os.Binder; |
| import android.os.IBinder; |
| import android.os.SystemClock; |
| import android.support.v4.app.NotificationCompat; |
| import android.util.SparseBooleanArray; |
| import android.widget.Adapter; |
| |
| import com.android.gallery3d.R; |
| import com.android.gallery3d.app.NotificationIds; |
| import com.android.gallery3d.data.MtpClient; |
| import com.android.gallery3d.ingest.ui.MtpBitmapCache; |
| import com.android.gallery3d.util.BucketNames; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.List; |
| |
| public class IngestService extends Service implements ImportTask.Listener, |
| MtpDeviceIndex.ProgressListener, MtpClient.Listener { |
| |
| public class LocalBinder extends Binder { |
| IngestService getService() { |
| return IngestService.this; |
| } |
| } |
| |
| private static final int PROGRESS_UPDATE_INTERVAL_MS = 180; |
| |
| private static MtpClient sClient; |
| |
| private final IBinder mBinder = new LocalBinder(); |
| private ScannerClient mScannerClient; |
| private MtpDevice mDevice; |
| private String mDevicePrettyName; |
| private MtpDeviceIndex mIndex; |
| private IngestActivity mClientActivity; |
| private boolean mRedeliverImportFinish = false; |
| private Collection<MtpObjectInfo> mRedeliverObjectsNotImported; |
| private boolean mRedeliverNotifyIndexChanged = false; |
| private NotificationManager mNotificationManager; |
| private NotificationCompat.Builder mNotificationBuilder; |
| private long mLastProgressIndexTime = 0; |
| |
| @Override |
| public void onCreate() { |
| super.onCreate(); |
| mScannerClient = new ScannerClient(this); |
| mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); |
| mNotificationBuilder = new NotificationCompat.Builder(this); |
| mNotificationBuilder.setSmallIcon(android.R.drawable.stat_notify_sync) // TODO drawable |
| .setContentIntent(PendingIntent.getActivity(this, 0, new Intent(this, IngestActivity.class), 0)); |
| mIndex = MtpDeviceIndex.getInstance(); |
| mIndex.setProgressListener(this); |
| |
| if (sClient == null) { |
| sClient = new MtpClient(getApplicationContext()); |
| } |
| List<MtpDevice> devices = sClient.getDeviceList(); |
| if (devices.size() > 0) { |
| setDevice(devices.get(0)); |
| } |
| sClient.addListener(this); |
| } |
| |
| @Override |
| public void onDestroy() { |
| sClient.removeListener(this); |
| mIndex.unsetProgressListener(this); |
| super.onDestroy(); |
| } |
| |
| @Override |
| public IBinder onBind(Intent intent) { |
| return mBinder; |
| } |
| |
| private void setDevice(MtpDevice device) { |
| if (mDevice == device) return; |
| mRedeliverImportFinish = false; |
| mRedeliverObjectsNotImported = null; |
| mRedeliverNotifyIndexChanged = false; |
| mDevice = device; |
| mIndex.setDevice(mDevice); |
| if (mDevice != null) { |
| MtpDeviceInfo deviceInfo = mDevice.getDeviceInfo(); |
| mDevicePrettyName = deviceInfo.getModel(); |
| mNotificationBuilder.setContentTitle(mDevicePrettyName); |
| new Thread(mIndex.getIndexRunnable()).start(); |
| } else { |
| mDevicePrettyName = null; |
| } |
| if (mClientActivity != null) { |
| mClientActivity.notifyIndexChanged(); |
| } else { |
| mRedeliverNotifyIndexChanged = true; |
| } |
| } |
| |
| protected MtpDeviceIndex getIndex() { |
| return mIndex; |
| } |
| |
| protected void setClientActivity(IngestActivity activity) { |
| if (mClientActivity == activity) return; |
| mClientActivity = activity; |
| if (mClientActivity == null) return; |
| mNotificationManager.cancel(NotificationIds.INGEST_NOTIFICATION_IMPORTING); |
| mNotificationManager.cancel(NotificationIds.INGEST_NOTIFICATION_SCANNING); |
| if (mRedeliverImportFinish) { |
| mClientActivity.onImportFinish(mRedeliverObjectsNotImported); |
| mRedeliverImportFinish = false; |
| mRedeliverObjectsNotImported = null; |
| } |
| if (mRedeliverNotifyIndexChanged) { |
| mClientActivity.notifyIndexChanged(); |
| mRedeliverNotifyIndexChanged = false; |
| } |
| } |
| |
| protected void importSelectedItems(SparseBooleanArray selected, Adapter adapter) { |
| List<MtpObjectInfo> importHandles = new ArrayList<MtpObjectInfo>(); |
| for (int i = 0; i < selected.size(); i++) { |
| if (selected.valueAt(i)) { |
| Object item = adapter.getItem(selected.keyAt(i)); |
| if (item instanceof MtpObjectInfo) { |
| importHandles.add(((MtpObjectInfo) item)); |
| } |
| } |
| } |
| ImportTask task = new ImportTask(mDevice, importHandles, BucketNames.IMPORTED, this); |
| task.setListener(this); |
| mNotificationBuilder.setProgress(0, 0, true) |
| .setContentText(getResources().getText(R.string.ingest_importing)); |
| startForeground(NotificationIds.INGEST_NOTIFICATION_IMPORTING, |
| mNotificationBuilder.build()); |
| new Thread(task).start(); |
| } |
| |
| @Override |
| public void deviceAdded(MtpDevice device) { |
| if (mDevice == null) { |
| setDevice(device); |
| } |
| } |
| |
| @Override |
| public void deviceRemoved(MtpDevice device) { |
| if (device == mDevice) { |
| setDevice(null); |
| } |
| MtpBitmapCache.onDeviceDisconnected(device); |
| } |
| |
| @Override |
| public void onImportProgress(int visitedCount, int totalCount, |
| String pathIfSuccessful) { |
| if (pathIfSuccessful != null) { |
| mScannerClient.scanPath(pathIfSuccessful); |
| } |
| if (mClientActivity != null) { |
| mClientActivity.onImportProgress(visitedCount, totalCount, pathIfSuccessful); |
| } |
| mNotificationBuilder.setProgress(totalCount, visitedCount, false) |
| .setContentText(getResources().getText(R.string.ingest_importing)); |
| mNotificationManager.notify(NotificationIds.INGEST_NOTIFICATION_IMPORTING, |
| mNotificationBuilder.build()); |
| } |
| |
| @Override |
| public void onImportFinish(Collection<MtpObjectInfo> objectsNotImported) { |
| if (mClientActivity != null) { |
| mClientActivity.onImportFinish(objectsNotImported); |
| } else { |
| mRedeliverImportFinish = true; |
| mRedeliverObjectsNotImported = objectsNotImported; |
| mNotificationBuilder.setProgress(0, 0, false) |
| .setContentText(getResources().getText(R.string.import_complete)); |
| mNotificationManager.notify(NotificationIds.INGEST_NOTIFICATION_IMPORTING, |
| mNotificationBuilder.build()); |
| } |
| stopForeground(mClientActivity != null); |
| } |
| |
| @Override |
| public void onObjectIndexed(MtpObjectInfo object, int numVisited) { |
| if (mClientActivity != null) { |
| mClientActivity.onObjectIndexed(object, numVisited); |
| } else { |
| // Throttle the updates to one every PROGRESS_UPDATE_INTERVAL_MS milliseconds |
| long currentTime = SystemClock.uptimeMillis(); |
| if (currentTime > mLastProgressIndexTime + PROGRESS_UPDATE_INTERVAL_MS) { |
| mLastProgressIndexTime = currentTime; |
| mNotificationBuilder.setProgress(0, numVisited, true) |
| .setContentText(getResources().getText(R.string.ingest_scanning)); |
| mNotificationManager.notify(NotificationIds.INGEST_NOTIFICATION_SCANNING, |
| mNotificationBuilder.build()); |
| } |
| } |
| } |
| |
| @Override |
| public void onSorting() { |
| if (mClientActivity != null) mClientActivity.onSorting(); |
| } |
| |
| @Override |
| public void onIndexFinish() { |
| if (mClientActivity != null) { |
| mClientActivity.onIndexFinish(); |
| } else { |
| mNotificationBuilder.setProgress(0, 0, false) |
| .setContentText(getResources().getText(R.string.ingest_scanning_done)); |
| mNotificationManager.notify(NotificationIds.INGEST_NOTIFICATION_SCANNING, |
| mNotificationBuilder.build()); |
| } |
| } |
| |
| // Copied from old Gallery3d code |
| private static final class ScannerClient implements MediaScannerConnectionClient { |
| ArrayList<String> mPaths = new ArrayList<String>(); |
| MediaScannerConnection mScannerConnection; |
| boolean mConnected; |
| Object mLock = new Object(); |
| |
| public ScannerClient(Context context) { |
| mScannerConnection = new MediaScannerConnection(context, this); |
| } |
| |
| public void scanPath(String path) { |
| synchronized (mLock) { |
| if (mConnected) { |
| mScannerConnection.scanFile(path, null); |
| } else { |
| mPaths.add(path); |
| mScannerConnection.connect(); |
| } |
| } |
| } |
| |
| @Override |
| public void onMediaScannerConnected() { |
| synchronized (mLock) { |
| mConnected = true; |
| if (!mPaths.isEmpty()) { |
| for (String path : mPaths) { |
| mScannerConnection.scanFile(path, null); |
| } |
| mPaths.clear(); |
| } |
| } |
| } |
| |
| @Override |
| public void onScanCompleted(String path, Uri uri) { |
| } |
| } |
| } |