VCardService.java revision 910d3e7854e657d20ab8c3a5a330b2a3188b1c74
1f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawa/* 2f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawa * Copyright (C) 2010 The Android Open Source Project 3f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawa * 4f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawa * Licensed under the Apache License, Version 2.0 (the "License"); 5f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawa * you may not use this file except in compliance with the License. 6f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawa * You may obtain a copy of the License at 7f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawa * 8f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawa * http://www.apache.org/licenses/LICENSE-2.0 9f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawa * 10f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawa * Unless required by applicable law or agreed to in writing, software 11f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawa * distributed under the License is distributed on an "AS IS" BASIS, 12f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawa * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawa * See the License for the specific language governing permissions and 14f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawa * limitations under the License. 15f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawa */ 161b918e58f4a3ae8d32af83f6f69bbf2de57a94f9Daisuke Miyakawapackage com.android.contacts.vcard; 17f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawa 187c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawaimport com.android.contacts.R; 197c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa 20f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawaimport android.app.Service; 21f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawaimport android.content.Intent; 22476004be0c4907b462b3d699671d9e1cff1a7bd7Daisuke Miyakawaimport android.os.Handler; 23f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawaimport android.os.IBinder; 24476004be0c4907b462b3d699671d9e1cff1a7bd7Daisuke Miyakawaimport android.os.Message; 25476004be0c4907b462b3d699671d9e1cff1a7bd7Daisuke Miyakawaimport android.os.Messenger; 26f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawaimport android.util.Log; 27f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawaimport android.widget.Toast; 28f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawa 297c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawaimport java.util.HashMap; 307c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawaimport java.util.Map; 317c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawaimport java.util.concurrent.ExecutorService; 327c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawaimport java.util.concurrent.Executors; 337c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawaimport java.util.concurrent.RejectedExecutionException; 341b918e58f4a3ae8d32af83f6f69bbf2de57a94f9Daisuke Miyakawa 35f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawa/** 367c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa * The class responsible for handling vCard import/export requests. 377c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa * 387c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa * This Service creates one ImportRequest/ExportRequest object (as Runnable) per request and push 397c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa * it to {@link ExecutorService} with single thread executor. The executor handles each request 407c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa * one by one, and notifies users when needed. 41f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawa */ 427c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa// TODO: Using IntentService looks simpler than using Service + ServiceConnection though this 437c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa// works fine enough. Investigate the feasibility. 44d8fb81a0024d30c027ea6ebf57d29d3ff10453fbDaisuke Miyakawapublic class VCardService extends Service { 457c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa private final static String LOG_TAG = "VCardService"; 46f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawa 47ef41f8866e8e7d52e04907f7282adcf5f4749f25Daisuke Miyakawa /* package */ static final int MSG_IMPORT_REQUEST = 1; 48d8fb81a0024d30c027ea6ebf57d29d3ff10453fbDaisuke Miyakawa /* package */ static final int MSG_EXPORT_REQUEST = 2; 4918b5190d6ed37be04d153a5d6f205076b38ac479Daisuke Miyakawa /* package */ static final int MSG_CANCEL_IMPORT_REQUEST = 3; 50f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawa 51d8fb81a0024d30c027ea6ebf57d29d3ff10453fbDaisuke Miyakawa /* package */ static final int IMPORT_NOTIFICATION_ID = 1000; 52d8fb81a0024d30c027ea6ebf57d29d3ff10453fbDaisuke Miyakawa /* package */ static final int EXPORT_NOTIFICATION_ID = 1001; 53f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawa 54aba4353bcf77ba91463cfd079feec3b6c6f59c5cDaisuke Miyakawa /* package */ static final String CACHE_FILE_PREFIX = "import_tmp_"; 55f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawa 56910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa private final Messenger mMessenger = new Messenger(new Handler() { 57476004be0c4907b462b3d699671d9e1cff1a7bd7Daisuke Miyakawa @Override 58476004be0c4907b462b3d699671d9e1cff1a7bd7Daisuke Miyakawa public void handleMessage(Message msg) { 59476004be0c4907b462b3d699671d9e1cff1a7bd7Daisuke Miyakawa switch (msg.what) { 60ef41f8866e8e7d52e04907f7282adcf5f4749f25Daisuke Miyakawa case MSG_IMPORT_REQUEST: { 617c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa handleImportRequest((ImportRequest)msg.obj); 62476004be0c4907b462b3d699671d9e1cff1a7bd7Daisuke Miyakawa break; 63915723665339c73c9bdebc7bf8ef56c414602c2cDaisuke Miyakawa } 64d8fb81a0024d30c027ea6ebf57d29d3ff10453fbDaisuke Miyakawa case MSG_EXPORT_REQUEST: { 657c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa handleExportRequest((ExportRequest)msg.obj); 66d8fb81a0024d30c027ea6ebf57d29d3ff10453fbDaisuke Miyakawa break; 67d8fb81a0024d30c027ea6ebf57d29d3ff10453fbDaisuke Miyakawa } 6818b5190d6ed37be04d153a5d6f205076b38ac479Daisuke Miyakawa case MSG_CANCEL_IMPORT_REQUEST: { 697c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa handleCancelAllImportRequest(); 7018b5190d6ed37be04d153a5d6f205076b38ac479Daisuke Miyakawa break; 7118b5190d6ed37be04d153a5d6f205076b38ac479Daisuke Miyakawa } 727c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa // TODO: add cancel capability for export.. 73d8fb81a0024d30c027ea6ebf57d29d3ff10453fbDaisuke Miyakawa default: { 74aba4353bcf77ba91463cfd079feec3b6c6f59c5cDaisuke Miyakawa Log.w(LOG_TAG, "Received unknown request, ignoring it."); 75476004be0c4907b462b3d699671d9e1cff1a7bd7Daisuke Miyakawa super.hasMessages(msg.what); 76d8fb81a0024d30c027ea6ebf57d29d3ff10453fbDaisuke Miyakawa } 77476004be0c4907b462b3d699671d9e1cff1a7bd7Daisuke Miyakawa } 78f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawa } 79910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa }); 80f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawa 817c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa // Should be single thread, as we don't want to simultaneously handle import and export 827c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa // requests. 83910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa private final ExecutorService mExecutorService = Executors.newSingleThreadExecutor(); 847c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa 857c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa private int mCurrentJobId; 86910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa 87910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa // Stores all unfinished import/export jobs which will be executed by mExecutorService. 88910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa // Key is jobId. 89910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa private final Map<Integer, ProcessorBase> mRunningJobMap = 90910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa new HashMap<Integer, ProcessorBase>(); 91476004be0c4907b462b3d699671d9e1cff1a7bd7Daisuke Miyakawa 92476004be0c4907b462b3d699671d9e1cff1a7bd7Daisuke Miyakawa @Override 93476004be0c4907b462b3d699671d9e1cff1a7bd7Daisuke Miyakawa public int onStartCommand(Intent intent, int flags, int id) { 94476004be0c4907b462b3d699671d9e1cff1a7bd7Daisuke Miyakawa return START_STICKY; 95f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawa } 96f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawa 97f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawa @Override 98f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawa public IBinder onBind(Intent intent) { 99476004be0c4907b462b3d699671d9e1cff1a7bd7Daisuke Miyakawa return mMessenger.getBinder(); 100f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawa } 101aba4353bcf77ba91463cfd079feec3b6c6f59c5cDaisuke Miyakawa 102aba4353bcf77ba91463cfd079feec3b6c6f59c5cDaisuke Miyakawa @Override 103aba4353bcf77ba91463cfd079feec3b6c6f59c5cDaisuke Miyakawa public void onDestroy() { 104910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa Log.i(LOG_TAG, "VCardService is being destroyed."); 105910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa cancelAllRequestsAndShutdown(); 106aba4353bcf77ba91463cfd079feec3b6c6f59c5cDaisuke Miyakawa clearCache(); 107aba4353bcf77ba91463cfd079feec3b6c6f59c5cDaisuke Miyakawa super.onDestroy(); 108aba4353bcf77ba91463cfd079feec3b6c6f59c5cDaisuke Miyakawa } 109aba4353bcf77ba91463cfd079feec3b6c6f59c5cDaisuke Miyakawa 1107c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa private synchronized void handleImportRequest(ImportRequest request) { 111910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa tryExecute(new ImportProcessor(this, request, mCurrentJobId), 112910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa R.string.vcard_import_will_start_message, 113910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa R.string.vcard_import_request_rejected_message); 1147c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa } 1157c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa 1167c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa private synchronized void handleExportRequest(ExportRequest request) { 117910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa tryExecute(new ExportProcessor(this, request, mCurrentJobId), 118910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa R.string.vcard_export_will_start_message, 119910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa R.string.vcard_export_request_rejected_message); 120910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa } 121910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa 122910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa /** 123910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa * Tries to call {@link ExecutorService#execute(Runnable)} toward a given processor and 124910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa * shows appropriate Toast using given resource ids. 125910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa * Updates relevant instances when successful. 126910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa */ 127910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa private synchronized void tryExecute(ProcessorBase processor, 128910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa int successfulMessageId, int rejectedMessageId) { 1297c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa try { 130910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa mExecutorService.execute(processor); 131910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa mRunningJobMap.put(mCurrentJobId, processor); 132910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa mCurrentJobId++; 133910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa // TODO: Ideally we should detect the current status of import/export and show 134910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa // "started" when we can import right now and show "will start" when we cannot. 135910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa Toast.makeText(this, getString(successfulMessageId), Toast.LENGTH_LONG).show(); 1367c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa } catch (RejectedExecutionException e) { 137910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa Log.w(LOG_TAG, "Failed to excetute a job.", e); 138910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa // TODO: a little unkind to show Toast in this case, which is shown just a moment. 139910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa // Ideally we should show some persistent something users can notice more easily. 140910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa Toast.makeText(this, getString(rejectedMessageId), Toast.LENGTH_LONG).show(); 1417c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa } 1427c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa } 1437c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa 144f219f6ee48c503bb2b628c3f2aeff53b15c5a947Daisuke Miyakawa private void handleCancelAllImportRequest() { 1457c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa Log.i(LOG_TAG, "Received cancel import request."); 146910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa cancelAllImportRequests(); 1477c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa } 1487c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa 149910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa private synchronized void cancelAllImportRequests() { 150910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa for (final Map.Entry<Integer, ProcessorBase> entry : mRunningJobMap.entrySet()) { 151910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa final ProcessorBase processor = entry.getValue(); 152910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa if (processor.getType() == ProcessorBase.PROCESSOR_TYPE_IMPORT) { 153910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa final int jobId = entry.getKey(); 154910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa processor.cancel(true); 155910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa mRunningJobMap.remove(jobId); 156910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa Log.i(LOG_TAG, String.format("Canceling job %d", jobId)); 157f219f6ee48c503bb2b628c3f2aeff53b15c5a947Daisuke Miyakawa } 1587c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa } 159f219f6ee48c503bb2b628c3f2aeff53b15c5a947Daisuke Miyakawa stopServiceWhenNoJob(); 1607c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa } 1617c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa 162910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa private synchronized void cancelAllExportRequests() { 163910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa for (final Map.Entry<Integer, ProcessorBase> entry : mRunningJobMap.entrySet()) { 164910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa final ProcessorBase processor = entry.getValue(); 165910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa if (processor.getType() == ProcessorBase.PROCESSOR_TYPE_EXPORT) { 166910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa final int jobId = entry.getKey(); 167910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa processor.cancel(true); 168910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa mRunningJobMap.remove(jobId); 169910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa Log.i(LOG_TAG, String.format("Canceling job %d", jobId)); 170f219f6ee48c503bb2b628c3f2aeff53b15c5a947Daisuke Miyakawa } 1717c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa } 172f219f6ee48c503bb2b628c3f2aeff53b15c5a947Daisuke Miyakawa stopServiceWhenNoJob(); 173f219f6ee48c503bb2b628c3f2aeff53b15c5a947Daisuke Miyakawa } 174f219f6ee48c503bb2b628c3f2aeff53b15c5a947Daisuke Miyakawa 175f219f6ee48c503bb2b628c3f2aeff53b15c5a947Daisuke Miyakawa /** 176f219f6ee48c503bb2b628c3f2aeff53b15c5a947Daisuke Miyakawa * Checks job list and call {@link #stopSelf()} when there's no job now. 177f219f6ee48c503bb2b628c3f2aeff53b15c5a947Daisuke Miyakawa * A new job cannot be submitted any more after this call. 178f219f6ee48c503bb2b628c3f2aeff53b15c5a947Daisuke Miyakawa */ 179f219f6ee48c503bb2b628c3f2aeff53b15c5a947Daisuke Miyakawa private synchronized void stopServiceWhenNoJob() { 180910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa if (mRunningJobMap.size() > 0) { 181910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa for (final Map.Entry<Integer, ProcessorBase> entry : mRunningJobMap.entrySet()) { 182f219f6ee48c503bb2b628c3f2aeff53b15c5a947Daisuke Miyakawa final int jobId = entry.getKey(); 183910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa final ProcessorBase processor = entry.getValue(); 184910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa if (processor.isDone()) { 185910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa mRunningJobMap.remove(jobId); 186f219f6ee48c503bb2b628c3f2aeff53b15c5a947Daisuke Miyakawa } else { 187f219f6ee48c503bb2b628c3f2aeff53b15c5a947Daisuke Miyakawa Log.i(LOG_TAG, String.format("Found unfinished job (id: %d)", jobId)); 188f219f6ee48c503bb2b628c3f2aeff53b15c5a947Daisuke Miyakawa return; 189f219f6ee48c503bb2b628c3f2aeff53b15c5a947Daisuke Miyakawa } 190f219f6ee48c503bb2b628c3f2aeff53b15c5a947Daisuke Miyakawa } 191f219f6ee48c503bb2b628c3f2aeff53b15c5a947Daisuke Miyakawa } 192f219f6ee48c503bb2b628c3f2aeff53b15c5a947Daisuke Miyakawa 193f219f6ee48c503bb2b628c3f2aeff53b15c5a947Daisuke Miyakawa Log.i(LOG_TAG, "No unfinished job. Stop this service."); 194f219f6ee48c503bb2b628c3f2aeff53b15c5a947Daisuke Miyakawa mExecutorService.shutdown(); 195f219f6ee48c503bb2b628c3f2aeff53b15c5a947Daisuke Miyakawa stopSelf(); 1967c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa } 1977c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa 1987c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa /* package */ synchronized void handleFinishImportNotification( 1997c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa int jobId, boolean successful) { 200910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa Log.v(LOG_TAG, String.format("Received vCard import finish notification (id: %d). " 2017c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa + "Result: %b", jobId, (successful ? "success" : "failure"))); 202910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa if (mRunningJobMap.remove(jobId) == null) { 2037c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa Log.w(LOG_TAG, String.format("Tried to remove unknown job (id: %d)", jobId)); 2047c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa } 205f219f6ee48c503bb2b628c3f2aeff53b15c5a947Daisuke Miyakawa stopServiceWhenNoJob(); 2067c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa } 2077c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa 2087c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa /* package */ synchronized void handleFinishExportNotification( 2097c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa int jobId, boolean successful) { 210910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa Log.v(LOG_TAG, String.format("Received vCard export finish notification (id: %d). " 2117c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa + "Result: %b", jobId, (successful ? "success" : "failure"))); 212910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa if (mRunningJobMap.remove(jobId) == null) { 2137c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa Log.w(LOG_TAG, String.format("Tried to remove unknown job (id: %d)", jobId)); 2147c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa } 215f219f6ee48c503bb2b628c3f2aeff53b15c5a947Daisuke Miyakawa stopServiceWhenNoJob(); 2167c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa } 2177c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa 2187c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa /** 219910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa * Cancels all the import/export requests and calls {@link ExecutorService#shutdown()}, which 220f219f6ee48c503bb2b628c3f2aeff53b15c5a947Daisuke Miyakawa * means this Service becomes no longer ready for import/export requests. 221f219f6ee48c503bb2b628c3f2aeff53b15c5a947Daisuke Miyakawa * 222f219f6ee48c503bb2b628c3f2aeff53b15c5a947Daisuke Miyakawa * Mainly called from onDestroy(). 2237c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa */ 224910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa private synchronized void cancelAllRequestsAndShutdown() { 225910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa for (final Map.Entry<Integer, ProcessorBase> entry : mRunningJobMap.entrySet()) { 226910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa entry.getValue().cancel(true); 2277c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa } 228910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa mRunningJobMap.clear(); 229f219f6ee48c503bb2b628c3f2aeff53b15c5a947Daisuke Miyakawa mExecutorService.shutdown(); 2307c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa } 2317c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa 2327c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa /** 2337c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa * Removes import caches stored locally. 2347c819a1a434e02c54f6d216aa3b1a0d08cc93f50Daisuke Miyakawa */ 235aba4353bcf77ba91463cfd079feec3b6c6f59c5cDaisuke Miyakawa private void clearCache() { 236910d3e7854e657d20ab8c3a5a330b2a3188b1c74Daisuke Miyakawa for (final String fileName : fileList()) { 237aba4353bcf77ba91463cfd079feec3b6c6f59c5cDaisuke Miyakawa if (fileName.startsWith(CACHE_FILE_PREFIX)) { 238aba4353bcf77ba91463cfd079feec3b6c6f59c5cDaisuke Miyakawa // We don't want to keep all the caches so we remove cache files old enough. 239aba4353bcf77ba91463cfd079feec3b6c6f59c5cDaisuke Miyakawa Log.i(LOG_TAG, "Remove a temporary file: " + fileName); 240aba4353bcf77ba91463cfd079feec3b6c6f59c5cDaisuke Miyakawa deleteFile(fileName); 241aba4353bcf77ba91463cfd079feec3b6c6f59c5cDaisuke Miyakawa } 242aba4353bcf77ba91463cfd079feec3b6c6f59c5cDaisuke Miyakawa } 243aba4353bcf77ba91463cfd079feec3b6c6f59c5cDaisuke Miyakawa } 244f21bf27c13dacec9b4ed74cba9046a64948e97fbDaisuke Miyakawa} 245