/* * Copyright 2013 Robotoworks Limited * 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.robotoworks.mechanoid.ops; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.Bundle; import android.os.DeadObjectException; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.util.Log; /* * Intent intent = GetApplicationVersionOperation.create(); * int id = Ops.execute(intent); * * Ops.registerListener(mListener); * * Ops.unregisterListener(mListener); * * OperationManager manager = OperationManager.create(getFragmentManager(), mCallbacks); * * Ops.execute(manager, OP_GET_VERSION, true, intent); */ public abstract class OperationService extends Service { protected static final String ACTION_ABORT = "com.robotoworks.mechanoid.op.actions.ABORT"; public static final String ACTION_BATCH = "com.robotoworks.mechanoid.op.actions.BATCH"; public static final String EXTRA_START_ID = "com.robotoworks.mechanoid.op.extras.START_ID"; public static final String EXTRA_REQUEST_ID = "com.robotoworks.mechanoid.op.extras.REQUEST_ID"; public static final String EXTRA_ABORT_REASON = "com.robotoworks.mechanoid.op.extras.ABORT_REASON"; public static final String EXTRA_BRIDGE_MESSENGER = "com.robotoworks.mechanoid.op.extras.BRIDGE_MESSENGER"; public static final String EXTRA_IS_ABORTED = "com.robotoworks.mechanoid.op.extras.IS_ABORTED"; public static final String EXTRA_BATCH = "com.robotoworks.mechanoid.op.extras.BATCH"; private static final int MSG_STOP = 1; protected final String mLogTag; protected final boolean mEnableLogging; class LocalBinder extends Binder { OperationService getService() { return OperationService.this; } } private Handler mHandler = new Handler() { public void handleMessage(Message msg) { if(msg.what == MSG_STOP) { stop(msg.arg1); } }; }; private IBinder mBinder = new LocalBinder(); private OperationProcessor mProcessor; private boolean mStopped; public boolean isStopped() { return mStopped; } public OperationService(boolean enableLogging) { mProcessor = createProcessor(); mLogTag = this.getClass().getSimpleName(); mEnableLogging = enableLogging; } protected abstract OperationProcessor createProcessor(); @Override public IBinder onBind(Intent intent) { return mBinder; } @Override public int onStartCommand(Intent intent, int flags, int startId) { if(mEnableLogging) { Log.d(mLogTag, String.format("[Start Command] startId:%s, intent:%s", startId, intent)); } if(intent != null) { intent.putExtra(EXTRA_START_ID, startId); handleIntent(intent); } return START_STICKY; } private void handleIntent(Intent intent) { mProcessor.execute(intent); } private void sendStopMessage(Intent request) { mHandler.removeMessages(MSG_STOP); int startId = request.getIntExtra(EXTRA_START_ID, 0); mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_STOP, startId, 0), getIdleStopTime()); } protected long getIdleStopTime() { return 10000; // 10 seconds } private void stop(int startId) { if(shouldStopOnAllOperationsComplete() && stopSelfResult(startId)) { if(mEnableLogging) { Log.d(mLogTag, String.format("[Stopping] startId:%s", startId)); } mStopped = true; } } @Override public void onDestroy() { super.onDestroy(); if(mEnableLogging) { Log.d(mLogTag, "[Destroying]"); } mProcessor.quit(); } protected boolean shouldStopOnAllOperationsComplete() { return true; } public void onOperationStarting(Intent request, Bundle data) { if(mEnableLogging) { Log.d(mLogTag, String.format("[Operation Starting] request:%s, data:%s", request, data)); } Messenger messenger = request.getParcelableExtra(EXTRA_BRIDGE_MESSENGER); Message m = new Message(); m.what = OperationServiceBridge.MSG_OPERATION_STARTING; m.arg1 = OperationServiceBridge.getOperationRequestId(request); m.setData(data); try { messenger.send(m); } catch (RemoteException e) { if(mEnableLogging) { Log.e(mLogTag, String.format("[Operation Exception] %s", Log.getStackTraceString(e))); } } } public void onOperationComplete(Intent request, Bundle data) { if(mEnableLogging) { Log.d(mLogTag, String.format("[Operation Complete] request:%s, data:%s", request, data)); } Messenger messenger = request.getParcelableExtra(EXTRA_BRIDGE_MESSENGER); Message m = new Message(); m.what = OperationServiceBridge.MSG_OPERATION_COMPLETE; m.arg1 = OperationServiceBridge.getOperationRequestId(request); m.setData(data); try { messenger.send(m); } catch (Exception e) { if(mEnableLogging) { Log.w(mLogTag, String.format("[Operation Exception] %s", Log.getStackTraceString(e))); } } sendStopMessage(request); } public void onOperationAborted(Intent request, int reason, Bundle data) { if(mEnableLogging) { Log.d(mLogTag, String.format("[Operation Aborted] request:%s, reason%s, data:%s", request, reason, data)); } Messenger messenger = request.getParcelableExtra(EXTRA_BRIDGE_MESSENGER); Message m = new Message(); m.what = OperationServiceBridge.MSG_OPERATION_ABORTED; m.arg1 = OperationServiceBridge.getOperationRequestId(request); m.arg2 = reason; m.setData(data); try { messenger.send(m); } catch (RemoteException e) { if(mEnableLogging) { Log.e(mLogTag, String.format("[Operation Exception] %s", Log.getStackTraceString(e))); } } sendStopMessage(request); } public void onOperationProgress(Intent request, int progress, Bundle data) { if(mEnableLogging) { Log.d(mLogTag, String.format("[Operation Progress] request:%s, progress:%s, data:%s", request, progress, data)); } Messenger messenger = request.getParcelableExtra(EXTRA_BRIDGE_MESSENGER); Message m = new Message(); m.what = OperationServiceBridge.MSG_OPERATION_PROGRESS; m.arg1 = OperationServiceBridge.getOperationRequestId(request); m.arg2 = progress; m.setData(data); try { messenger.send(m); } catch (RemoteException e) { if(mEnableLogging) { Log.e(mLogTag, String.format("[Operation Exception] %s", Log.getStackTraceString(e))); } } } }