1 /*
2  * Copyright (C) 2013 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.android.testing.sleephelper;
18 
19 import android.app.Activity;
20 import android.app.Instrumentation;
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.Debug;
27 import android.os.IBinder;
28 import android.os.RemoteException;
29 import android.util.Log;
30 
31 import com.android.testing.alarmservice.Alarm;
32 
33 public class SetAlarm extends Instrumentation {
34 
35     private static final String COMMAND = "command";
36     private static final String PARAM = "param";
37     private static final String CMD_PREPARE = "prepare";
38     private static final String CMD_SET = "set_wait";
39     private static final String CMD_DONE = "done";
40     private static final String SERVICE_ACTION = "com.android.testing.ALARM_SERVICE";
41     private static final String SERVICE_PKG = "com.android.testing.alarmservice";
42     private static final String LOG_TAG = SetAlarm.class.getSimpleName();
43 
44     private Alarm mAlarmService = null;
45     private Bundle mArgs = null;
46     private String mCommand = null;
47     private Intent mServceIntent = new Intent(SERVICE_ACTION).setPackage(SERVICE_PKG);
48 
49     private ServiceConnection mConn = new ServiceConnection() {
50         @Override
51         public void onServiceDisconnected(ComponentName name) {
52             Log.d(LOG_TAG, "Service disconnected.");
53             mAlarmService = null;
54             errorFinish("service disconnected");
55         }
56 
57         @Override
58         public void onServiceConnected(ComponentName name, IBinder service) {
59             Log.d(LOG_TAG, "Service connected.");
60             mAlarmService = Alarm.Stub.asInterface(service);
61             handleCommands();
62         }
63     };
64 
65 
handleCommands()66     private void handleCommands() {
67         if (CMD_PREPARE.equals(mCommand)) {
68             callPrepare();
69         } else if (CMD_SET.equals(mCommand)) {
70             String paramString = mArgs.getString(PARAM);
71             if (paramString == null) {
72                 errorFinish("argument expected for alarm time");
73             }
74             long timeout = -1;
75             try {
76                 timeout = Long.parseLong(paramString);
77             } catch (NumberFormatException nfe) {
78                 errorFinish("a number argument is expected");
79             }
80             callSetAndWait(timeout);
81         } else if (CMD_DONE.equals(mCommand)) {
82             callDone();
83         } else {
84             errorFinish("Unrecognized command: " + mCommand);
85         }
86         finish(Activity.RESULT_OK, new Bundle());
87     }
88 
89     @Override
onCreate(Bundle arguments)90     public void onCreate(Bundle arguments) {
91         super.onCreate(arguments);
92         mCommand = arguments.getString(COMMAND);
93         if ("true".equals(arguments.getString("debug"))) {
94             Debug.waitForDebugger();
95         }
96         if (mCommand == null) {
97             errorFinish("No command specified");
98         }
99         mArgs = arguments;
100         connectToAlarmService();
101     }
102 
errorFinish(String msg)103     private void errorFinish(String msg) {
104         Bundle ret = new Bundle();
105         ret.putString("error", msg);
106         finish(Activity.RESULT_CANCELED, ret);
107     }
108 
connectToAlarmService()109     private void connectToAlarmService() {
110         // start the service with an intent, this ensures the service keeps running after unbind
111         ComponentName cn = getContext().startService(mServceIntent);
112         if (cn == null) {
113             errorFinish("failed to start service");
114         }
115         if (!getContext().bindService(mServceIntent, mConn, Context.BIND_AUTO_CREATE)) {
116             errorFinish("failed to bind service");
117         }
118     }
119 
callPrepare()120     private void callPrepare() {
121         try {
122             mAlarmService.prepare();
123         } catch (RemoteException e) {
124             errorFinish("RemoteExeption in prepare()");
125         } finally {
126             getContext().unbindService(mConn);
127         }
128     }
129 
callDone()130     private void callDone() {
131         try {
132             mAlarmService.done();
133         } catch (RemoteException e) {
134             errorFinish("RemoteExeption in prepare()");
135         } finally {
136             getContext().unbindService(mConn);
137         }
138         // explicitly stop the service (started in prepare()) so that the service is now free
139         // to be reclaimed
140         getContext().stopService(mServceIntent);
141     }
142 
callSetAndWait(long timeoutMills)143     private void callSetAndWait(long timeoutMills) {
144         try {
145             mAlarmService.setAlarmAndWait(timeoutMills);
146         } catch (RemoteException e) {
147             errorFinish("RemoteExeption in setAlarmAndWait()");
148         } finally {
149             getContext().unbindService(mConn);
150         }
151     }
152 }
153