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 android.cts.tagging;
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.cts.tagging.TestingService;
25 import android.os.Handler;
26 import android.os.IBinder;
27 import android.os.Message;
28 import android.os.Messenger;
29 import android.os.RemoteException;
30 import android.util.Log;
31 
32 public class ServiceRunnerActivity extends Activity {
33   private static String TAG = ServiceRunnerActivity.class.getName();
34 
35   private Messenger mService;
36   private boolean mIsBound;
37 
38   private int mResult;
39   private final Object mFinishEvent = new Object();
40 
getResult()41   public synchronized int getResult() { return mResult; }
42 
43   // Handler of incoming messages from service.
44   class IncomingHandler extends Handler {
45     private ServiceRunnerActivity mActivity;
46 
IncomingHandler(ServiceRunnerActivity activity)47     IncomingHandler(ServiceRunnerActivity activity) { mActivity = activity; }
48 
49     @Override
handleMessage(Message msg)50     public void handleMessage(Message msg) {
51       switch (msg.what) {
52         case TestingService.MSG_NOTIFY_TEST_RESULT:
53           synchronized (mActivity.mFinishEvent) {
54             mActivity.mResult = msg.arg1;
55             mFinishEvent.notify();
56           }
57           doUnbindService();
58           break;
59         default:
60           super.handleMessage(msg);
61           return;
62       }
63     }
64   }
65 
66   // Target we publish for clients to send messages to IncomingHandler.
67   final Messenger mMessenger = new Messenger(new IncomingHandler(this));
68 
69   private ServiceConnection mConnection = new ServiceConnection() {
70     @Override
71     public void onServiceConnected(ComponentName className, IBinder service) {
72       mService = new Messenger(service);
73 
74       // Send a message to the service to register.
75       try {
76         Message msg = Message.obtain(null, TestingService.MSG_START_TEST);
77         msg.replyTo = mMessenger;
78         mService.send(msg);
79       } catch (RemoteException e) {
80         // In this case the service has crashed before we could even do anything.
81         Log.e(TAG, "Failed to send start message to service.");
82       }
83     }
84 
85     @Override
86     public void onServiceDisconnected(ComponentName className) {
87       // This is called when the connection with the service has been unexpectedly
88       // disconnected -- that is, its process crashed.
89       Log.i(TAG, "Service disconnected.");
90       mService = null;
91       synchronized (mFinishEvent) {
92         mResult = TestingService.RESULT_TEST_CRASHED;
93         mFinishEvent.notify();
94       }
95     }
96   };
97 
doUnbindService()98   void doUnbindService() {
99     // Detach our existing connection.
100     unbindService(mConnection);
101     mIsBound = false;
102   }
103 
runExternalService(ComponentName component)104   public void runExternalService(ComponentName component) throws Exception {
105     Intent intent = new Intent();
106     intent.setComponent(component);
107     runServiceCommon(intent, true);
108   }
109 
runService(Class<?> cls)110   public void runService(Class<?> cls) throws Exception {
111     Intent intent = new Intent(this, cls);
112     runServiceCommon(intent, false);
113   }
114 
runServiceCommon(Intent intent, boolean external)115   void runServiceCommon(Intent intent, boolean external) throws Exception {
116     mResult = TestingService.RESULT_TEST_UNKNOWN;
117     int flags = Context.BIND_AUTO_CREATE;
118     if (external)
119       flags |= Context.BIND_EXTERNAL_SERVICE;
120     boolean result = bindService(intent, mConnection, flags);
121     if (result == false) {
122       mResult = TestingService.RESULT_TEST_BIND_FAILED;
123       return;
124     }
125 
126     mIsBound = true;
127     Thread thread = new Thread() {
128       @Override
129       public void run() {
130         synchronized (mFinishEvent) {
131           while (mResult == TestingService.RESULT_TEST_UNKNOWN) {
132             try {
133               mFinishEvent.wait();
134             } catch (InterruptedException e) {
135             }
136           }
137         }
138       }
139     };
140     thread.start();
141     thread.join(50000 /* millis */);
142   }
143 }
144