/* * Copyright (C) 2012 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.tools.sdkcontroller.activities; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.IBinder; import android.util.Log; import com.android.tools.sdkcontroller.service.ControllerService; import com.android.tools.sdkcontroller.service.ControllerService.ControllerBinder; import com.android.tools.sdkcontroller.service.ControllerService.ControllerListener; /** * Base activity class that knows how to bind and unbind from the * {@link ControllerService}. */ public abstract class BaseBindingActivity extends Activity { public static String TAG = BaseBindingActivity.class.getSimpleName(); private static boolean DEBUG = true; private ServiceConnection mServiceConnection; private ControllerBinder mServiceBinder; /** * Returns the binder. Activities can use that to query the controller service. * @return An existing {@link ControllerBinder}. * The binder is only valid between calls {@link #onServiceConnected()} and * {@link #onServiceDisconnected()}. Returns null when not valid. */ public ControllerBinder getServiceBinder() { return mServiceBinder; } /** * Called when the activity resumes. * This automatically binds to the service, starting it as needed. * <p/> * Since on resume we automatically bind to the service, the {@link ServiceConnection} * will is restored and {@link #onServiceConnected()} is called as necessary. * Derived classes that need to initialize anything that is related to the service * (e.g. getting their handler) should thus do so in {@link #onServiceConnected()} and * <em>not</em> in {@link #onResume()} -- since binding to the service is asynchronous * there is <em>no</em> guarantee that {@link #getServiceBinder()} returns non-null * when this call finishes. */ @Override protected void onResume() { super.onResume(); bindToService(); } /** * Called when the activity is paused. * This automatically unbinds from the service but does not stop it. */ @Override protected void onPause() { super.onPause(); unbindFromService(); } // ---------- /** * Called when binding to the service to get the activity's {@link ControllerListener}. * @return A new non-null {@link ControllerListener}. */ protected abstract ControllerListener createControllerListener(); /** * Called by the service once the activity is connected (bound) to it. * <p/> * When this is called, {@link #getServiceBinder()} returns a non-null binder that * can be used by the activity to control the service. */ protected abstract void onServiceConnected(); /** * Called by the service when it is forcibly disconnected OR when we know * we're unbinding the service. * <p/> * When this is called, {@link #getServiceBinder()} returns a null binder and * the activity should stop using that binder and remove any reference to it. */ protected abstract void onServiceDisconnected(); /** * Starts the service and binds to it. */ protected void bindToService() { if (mServiceConnection == null) { final ControllerListener listener = createControllerListener(); mServiceConnection = new ServiceConnection() { /** * Called when the service is connected. * Allows us to retrieve the binder to talk to the service. */ @Override public void onServiceConnected(ComponentName name, IBinder service) { if (DEBUG) Log.d(TAG, "Activity connected to service"); mServiceBinder = (ControllerBinder) service; mServiceBinder.addControllerListener(listener); BaseBindingActivity.this.onServiceConnected(); } /** * Called when the service got disconnected, e.g. because it crashed. * This is <em>not</em> called when we unbind from the service. */ @Override public void onServiceDisconnected(ComponentName name) { if (DEBUG) Log.d(TAG, "Activity disconnected from service"); mServiceBinder = null; BaseBindingActivity.this.onServiceDisconnected(); } }; } // Start service so that it doesn't stop when we unbind if (DEBUG) Log.d(TAG, "start requested & bind service"); Intent service = new Intent(this, ControllerService.class); startService(service); bindService(service, mServiceConnection, Context.BIND_AUTO_CREATE); } /** * Unbinds from the service but does not actually stop the service. * This lets us have it run in the background even if this isn't the active activity. */ protected void unbindFromService() { if (mServiceConnection != null) { if (DEBUG) Log.d(TAG, "unbind service"); mServiceConnection.onServiceDisconnected(null /*name*/); unbindService(mServiceConnection); mServiceConnection = null; } } }