Home | History | Annotate | Download | only in activities
      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      */
     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
     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
     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      */
     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      */
     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      */
    103     protected abstract void onServiceDisconnected();
    104 
    105     /**
    106      * Starts the service and binds to it.
    107      */
    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      */
    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 }