1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of 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,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.example.android.apis.app;
18 
19 import android.app.Activity;
20 import android.app.Service;
21 import android.content.ComponentName;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.ServiceConnection;
25 import android.os.Bundle;
26 import android.os.RemoteException;
27 import android.os.IBinder;
28 import android.os.RemoteCallbackList;
29 import android.util.Log;
30 import android.view.View;
31 import android.view.View.OnClickListener;
32 import android.widget.Button;
33 import android.widget.CheckBox;
34 import android.widget.TextView;
35 
36 // Need the following import to get access to the app resources, since this
37 // class is in a sub-package.
38 import com.example.android.apis.R;
39 
40 /**
41  * This is an example if implementing a Service that uses android:isolatedProcess.
42  */
43 public class IsolatedService extends Service {
44     /**
45      * This is a list of callbacks that have been registered with the
46      * service.  Note that this is package scoped (instead of private) so
47      * that it can be accessed more efficiently from inner classes.
48      */
49     final RemoteCallbackList<IRemoteServiceCallback> mCallbacks
50             = new RemoteCallbackList<IRemoteServiceCallback>();
51 
52     int mValue = 0;
53 
54     @Override
onCreate()55     public void onCreate() {
56         Log.i("IsolatedService", "Creating IsolatedService: " + this);
57     }
58 
59     @Override
onDestroy()60     public void onDestroy() {
61         Log.i("IsolatedService", "Destroying IsolatedService: " + this);
62         // Unregister all callbacks.
63         mCallbacks.kill();
64     }
65 
66     @Override
onBind(Intent intent)67     public IBinder onBind(Intent intent) {
68         return mBinder;
69     }
70 
71     /**
72      * The IRemoteInterface is defined through IDL
73      */
74     private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
75         public void registerCallback(IRemoteServiceCallback cb) {
76             if (cb != null) mCallbacks.register(cb);
77         }
78         public void unregisterCallback(IRemoteServiceCallback cb) {
79             if (cb != null) mCallbacks.unregister(cb);
80         }
81     };
82 
83     @Override
onTaskRemoved(Intent rootIntent)84     public void onTaskRemoved(Intent rootIntent) {
85         Log.i("IsolatedService", "Task removed in " + this + ": " + rootIntent);
86         stopSelf();
87     }
88 
broadcastValue(int value)89     private void broadcastValue(int value) {
90         // Broadcast to all clients the new value.
91         final int N = mCallbacks.beginBroadcast();
92         for (int i=0; i<N; i++) {
93             try {
94                 mCallbacks.getBroadcastItem(i).valueChanged(value);
95             } catch (RemoteException e) {
96                 // The RemoteCallbackList will take care of removing
97                 // the dead object for us.
98             }
99         }
100         mCallbacks.finishBroadcast();
101     }
102 
103     // ----------------------------------------------------------------------
104 
105     public static class Controller extends Activity {
106         static class ServiceInfo {
107             final Activity mActivity;
108             final Class<?> mClz;
109             final TextView mStatus;
110             boolean mServiceBound;
111             IRemoteService mService;
112 
ServiceInfo(Activity activity, Class<?> clz, int start, int stop, int bind, int status)113             ServiceInfo(Activity activity, Class<?> clz,
114                     int start, int stop, int bind, int status) {
115                 mActivity = activity;
116                 mClz = clz;
117                 Button button = (Button)mActivity.findViewById(start);
118                 button.setOnClickListener(mStartListener);
119                 button = (Button)mActivity.findViewById(stop);
120                 button.setOnClickListener(mStopListener);
121                 CheckBox cb = (CheckBox)mActivity.findViewById(bind);
122                 cb.setOnClickListener(mBindListener);
123                 mStatus = (TextView)mActivity.findViewById(status);
124             }
125 
destroy()126             void destroy() {
127                 if (mServiceBound) {
128                     mActivity.unbindService(mConnection);
129                 }
130             }
131 
132             private OnClickListener mStartListener = new OnClickListener() {
133                 public void onClick(View v) {
134                     mActivity.startService(new Intent(mActivity, mClz));
135                 }
136             };
137 
138             private OnClickListener mStopListener = new OnClickListener() {
139                 public void onClick(View v) {
140                     mActivity.stopService(new Intent(mActivity, mClz));
141                 }
142             };
143 
144             private OnClickListener mBindListener = new OnClickListener() {
145                 public void onClick(View v) {
146                     if (((CheckBox)v).isChecked()) {
147                         if (!mServiceBound) {
148                             if (mActivity.bindService(new Intent(mActivity, mClz),
149                                     mConnection, Context.BIND_AUTO_CREATE)) {
150                                 mServiceBound = true;
151                                 mStatus.setText("BOUND");
152                             }
153                         }
154                     } else {
155                         if (mServiceBound) {
156                             mActivity.unbindService(mConnection);
157                             mServiceBound = false;
158                             mStatus.setText("");
159                         }
160                     }
161                 }
162             };
163 
164             private ServiceConnection mConnection = new ServiceConnection() {
165                 public void onServiceConnected(ComponentName className,
166                         IBinder service) {
167                     mService = IRemoteService.Stub.asInterface(service);
168                     if (mServiceBound) {
169                         mStatus.setText("CONNECTED");
170                     }
171                 }
172 
173                 public void onServiceDisconnected(ComponentName className) {
174                     // This is called when the connection with the service has been
175                     // unexpectedly disconnected -- that is, its process crashed.
176                     mService = null;
177                     if (mServiceBound) {
178                         mStatus.setText("DISCONNECTED");
179                     }
180                 }
181             };
182         }
183 
184         ServiceInfo mService1;
185         ServiceInfo mService2;
186 
187         @Override
onCreate(Bundle savedInstanceState)188         protected void onCreate(Bundle savedInstanceState) {
189             super.onCreate(savedInstanceState);
190 
191             setContentView(R.layout.isolated_service_controller);
192 
193             mService1 = new ServiceInfo(this, IsolatedService.class, R.id.start1, R.id.stop1,
194                     R.id.bind1, R.id.status1);
195             mService2 = new ServiceInfo(this, IsolatedService2.class, R.id.start2, R.id.stop2,
196                     R.id.bind2, R.id.status2);
197         }
198 
199         @Override
onDestroy()200         protected void onDestroy() {
201             super.onDestroy();
202             mService1.destroy();
203             mService2.destroy();
204         }
205     }
206 }
207