1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17 package com.android.tools.sdkcontroller.activities; 18 19 import android.app.Activity; 20 import android.content.ComponentName; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.ServiceConnection; 24 import android.os.IBinder; 25 import android.util.Log; 26 27 import com.android.tools.sdkcontroller.service.ControllerService; 28 import com.android.tools.sdkcontroller.service.ControllerService.ControllerBinder; 29 import com.android.tools.sdkcontroller.service.ControllerService.ControllerListener; 30 31 /** 32 * Base activity class that knows how to bind and unbind from the 33 * {@link ControllerService}. 34 */ 35 public abstract class BaseBindingActivity extends Activity { 36 37 public static String TAG = BaseBindingActivity.class.getSimpleName(); 38 private static boolean DEBUG = true; 39 private ServiceConnection mServiceConnection; 40 private ControllerBinder mServiceBinder; 41 42 /** 43 * Returns the binder. Activities can use that to query the controller service. 44 * @return An existing {@link ControllerBinder}. 45 * The binder is only valid between calls {@link #onServiceConnected()} and 46 * {@link #onServiceDisconnected()}. Returns null when not valid. 47 */ getServiceBinder()48 public ControllerBinder getServiceBinder() { 49 return mServiceBinder; 50 } 51 52 /** 53 * Called when the activity resumes. 54 * This automatically binds to the service, starting it as needed. 55 * <p/> 56 * Since on resume we automatically bind to the service, the {@link ServiceConnection} 57 * will is restored and {@link #onServiceConnected()} is called as necessary. 58 * Derived classes that need to initialize anything that is related to the service 59 * (e.g. getting their handler) should thus do so in {@link #onServiceConnected()} and 60 * <em>not</em> in {@link #onResume()} -- since binding to the service is asynchronous 61 * there is <em>no</em> guarantee that {@link #getServiceBinder()} returns non-null 62 * when this call finishes. 63 */ 64 @Override onResume()65 protected void onResume() { 66 super.onResume(); 67 bindToService(); 68 } 69 70 /** 71 * Called when the activity is paused. 72 * This automatically unbinds from the service but does not stop it. 73 */ 74 @Override onPause()75 protected void onPause() { 76 super.onPause(); 77 unbindFromService(); 78 } 79 80 // ---------- 81 82 /** 83 * Called when binding to the service to get the activity's {@link ControllerListener}. 84 * @return A new non-null {@link ControllerListener}. 85 */ createControllerListener()86 protected abstract ControllerListener createControllerListener(); 87 88 /** 89 * Called by the service once the activity is connected (bound) to it. 90 * <p/> 91 * When this is called, {@link #getServiceBinder()} returns a non-null binder that 92 * can be used by the activity to control the service. 93 */ onServiceConnected()94 protected abstract void onServiceConnected(); 95 96 /** 97 * Called by the service when it is forcibly disconnected OR when we know 98 * we're unbinding the service. 99 * <p/> 100 * When this is called, {@link #getServiceBinder()} returns a null binder and 101 * the activity should stop using that binder and remove any reference to it. 102 */ onServiceDisconnected()103 protected abstract void onServiceDisconnected(); 104 105 /** 106 * Starts the service and binds to it. 107 */ bindToService()108 protected void bindToService() { 109 if (mServiceConnection == null) { 110 final ControllerListener listener = createControllerListener(); 111 112 mServiceConnection = new ServiceConnection() { 113 /** 114 * Called when the service is connected. 115 * Allows us to retrieve the binder to talk to the service. 116 */ 117 @Override 118 public void onServiceConnected(ComponentName name, IBinder service) { 119 if (DEBUG) Log.d(TAG, "Activity connected to service"); 120 mServiceBinder = (ControllerBinder) service; 121 mServiceBinder.addControllerListener(listener); 122 BaseBindingActivity.this.onServiceConnected(); 123 } 124 125 /** 126 * Called when the service got disconnected, e.g. because it crashed. 127 * This is <em>not</em> called when we unbind from the service. 128 */ 129 @Override 130 public void onServiceDisconnected(ComponentName name) { 131 if (DEBUG) Log.d(TAG, "Activity disconnected from service"); 132 mServiceBinder = null; 133 BaseBindingActivity.this.onServiceDisconnected(); 134 } 135 }; 136 } 137 138 // Start service so that it doesn't stop when we unbind 139 if (DEBUG) Log.d(TAG, "start requested & bind service"); 140 Intent service = new Intent(this, ControllerService.class); 141 startService(service); 142 bindService(service, 143 mServiceConnection, 144 Context.BIND_AUTO_CREATE); 145 } 146 147 /** 148 * Unbinds from the service but does not actually stop the service. 149 * This lets us have it run in the background even if this isn't the active activity. 150 */ unbindFromService()151 protected void unbindFromService() { 152 if (mServiceConnection != null) { 153 if (DEBUG) Log.d(TAG, "unbind service"); 154 mServiceConnection.onServiceDisconnected(null /*name*/); 155 unbindService(mServiceConnection); 156 mServiceConnection = null; 157 } 158 } 159 }