Roll NDK to pick std::deque patch.
[android_tools.git] / sdk / tools / apps / SdkController / src / com / android / tools / sdkcontroller / activities / SensorActivity.java
blob61c30815283ecbd3d90793b1806d2c68481da772
1 /*
2 * Copyright (C) 2012 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.tools.sdkcontroller.activities;
19 import java.util.HashMap;
20 import java.util.List;
21 import java.util.Map;
23 import android.os.Bundle;
24 import android.os.Message;
25 import android.util.Log;
26 import android.view.KeyEvent;
27 import android.view.LayoutInflater;
28 import android.view.View;
29 import android.view.View.OnFocusChangeListener;
30 import android.view.View.OnKeyListener;
31 import android.widget.CheckBox;
32 import android.widget.CompoundButton;
33 import android.widget.TableLayout;
34 import android.widget.TableRow;
35 import android.widget.TextView;
37 import com.android.tools.sdkcontroller.R;
38 import com.android.tools.sdkcontroller.handlers.SensorChannel;
39 import com.android.tools.sdkcontroller.handlers.SensorChannel.MonitoredSensor;
40 import com.android.tools.sdkcontroller.lib.Channel;
41 import com.android.tools.sdkcontroller.service.ControllerService.ControllerBinder;
42 import com.android.tools.sdkcontroller.service.ControllerService.ControllerListener;
44 /**
45 * Activity that displays and controls the sensors from {@link SensorChannel}.
46 * For each sensor it displays a checkbox that is enabled if the sensor is supported
47 * by the emulator. The user can select whether the sensor is active. It also displays
48 * data from the sensor when available.
50 public class SensorActivity extends BaseBindingActivity
51 implements android.os.Handler.Callback {
53 @SuppressWarnings("hiding")
54 public static String TAG = SensorActivity.class.getSimpleName();
55 private static boolean DEBUG = true;
57 private static final int MSG_UPDATE_ACTUAL_HZ = 0x31415;
59 private TableLayout mTableLayout;
60 private TextView mTextError;
61 private TextView mTextStatus;
62 private TextView mTextTargetHz;
63 private TextView mTextActualHz;
64 private SensorChannel mSensorHandler;
66 private final Map<MonitoredSensor, DisplayInfo> mDisplayedSensors =
67 new HashMap<SensorChannel.MonitoredSensor, SensorActivity.DisplayInfo>();
68 private final android.os.Handler mUiHandler = new android.os.Handler(this);
69 private int mTargetSampleRate;
70 private long mLastActualUpdateMs;
72 /** Called when the activity is first created. */
73 @Override
74 public void onCreate(Bundle savedInstanceState) {
75 super.onCreate(savedInstanceState);
76 setContentView(R.layout.sensors);
77 mTableLayout = (TableLayout) findViewById(R.id.tableLayout);
78 mTextError = (TextView) findViewById(R.id.textError);
79 mTextStatus = (TextView) findViewById(R.id.textStatus);
80 mTextTargetHz = (TextView) findViewById(R.id.textSampleRate);
81 mTextActualHz = (TextView) findViewById(R.id.textActualRate);
82 updateStatus("Waiting for connection");
84 mTextTargetHz.setOnKeyListener(new OnKeyListener() {
85 @Override
86 public boolean onKey(View v, int keyCode, KeyEvent event) {
87 updateSampleRate();
88 return false;
90 });
91 mTextTargetHz.setOnFocusChangeListener(new OnFocusChangeListener() {
92 @Override
93 public void onFocusChange(View v, boolean hasFocus) {
94 updateSampleRate();
96 });
99 @Override
100 protected void onResume() {
101 if (DEBUG) Log.d(TAG, "onResume");
102 // BaseBindingActivity.onResume will bind to the service.
103 super.onResume();
104 updateError();
107 @Override
108 protected void onPause() {
109 if (DEBUG) Log.d(TAG, "onPause");
110 // BaseBindingActivity.onResume will unbind from (but not stop) the service.
111 super.onPause();
114 @Override
115 protected void onDestroy() {
116 if (DEBUG) Log.d(TAG, "onDestroy");
117 super.onDestroy();
118 removeSensorUi();
121 // ----------
123 @Override
124 protected void onServiceConnected() {
125 if (DEBUG) Log.d(TAG, "onServiceConnected");
126 createSensorUi();
129 @Override
130 protected void onServiceDisconnected() {
131 if (DEBUG) Log.d(TAG, "onServiceDisconnected");
132 removeSensorUi();
135 @Override
136 protected ControllerListener createControllerListener() {
137 return new SensorsControllerListener();
140 // ----------
142 private class SensorsControllerListener implements ControllerListener {
143 @Override
144 public void onErrorChanged() {
145 runOnUiThread(new Runnable() {
146 @Override
147 public void run() {
148 updateError();
153 @Override
154 public void onStatusChanged() {
155 runOnUiThread(new Runnable() {
156 @Override
157 public void run() {
158 ControllerBinder binder = getServiceBinder();
159 if (binder != null) {
160 boolean connected = binder.isEmuConnected();
161 mTableLayout.setEnabled(connected);
162 updateStatus(connected ? "Emulated connected" : "Emulator disconnected");
169 private void createSensorUi() {
170 final LayoutInflater inflater = getLayoutInflater();
172 if (!mDisplayedSensors.isEmpty()) {
173 removeSensorUi();
176 mSensorHandler = (SensorChannel) getServiceBinder().getChannel(Channel.SENSOR_CHANNEL);
177 if (mSensorHandler != null) {
178 mSensorHandler.addUiHandler(mUiHandler);
179 mUiHandler.sendEmptyMessage(MSG_UPDATE_ACTUAL_HZ);
181 assert mDisplayedSensors.isEmpty();
182 List<MonitoredSensor> sensors = mSensorHandler.getSensors();
183 for (MonitoredSensor sensor : sensors) {
184 final TableRow row = (TableRow) inflater.inflate(R.layout.sensor_row,
185 mTableLayout,
186 false);
187 mTableLayout.addView(row);
188 mDisplayedSensors.put(sensor, new DisplayInfo(sensor, row));
193 private void removeSensorUi() {
194 if (mSensorHandler != null) {
195 mSensorHandler.removeUiHandler(mUiHandler);
196 mSensorHandler = null;
198 mTableLayout.removeAllViews();
199 for (DisplayInfo info : mDisplayedSensors.values()) {
200 info.release();
202 mDisplayedSensors.clear();
205 private class DisplayInfo implements CompoundButton.OnCheckedChangeListener {
206 private MonitoredSensor mSensor;
207 private CheckBox mChk;
208 private TextView mVal;
210 public DisplayInfo(MonitoredSensor sensor, TableRow row) {
211 mSensor = sensor;
213 // Initialize displayed checkbox for this sensor, and register
214 // checked state listener for it.
215 mChk = (CheckBox) row.findViewById(R.id.row_checkbox);
216 mChk.setText(sensor.getUiName());
217 mChk.setEnabled(sensor.isEnabledByEmulator());
218 mChk.setChecked(sensor.isEnabledByUser());
219 mChk.setOnCheckedChangeListener(this);
221 // Initialize displayed text box for this sensor.
222 mVal = (TextView) row.findViewById(R.id.row_textview);
223 mVal.setText(sensor.getValue());
227 * Handles checked state change for the associated CheckBox. If check
228 * box is checked we will register sensor change listener. If it is
229 * unchecked, we will unregister sensor change listener.
231 @Override
232 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
233 if (mSensor != null) {
234 mSensor.onCheckedChanged(isChecked);
238 public void release() {
239 mChk = null;
240 mVal = null;
241 mSensor = null;
245 public void updateState() {
246 if (mChk != null && mSensor != null) {
247 mChk.setEnabled(mSensor.isEnabledByEmulator());
248 mChk.setChecked(mSensor.isEnabledByUser());
252 public void updateValue() {
253 if (mVal != null && mSensor != null) {
254 mVal.setText(mSensor.getValue());
259 /** Implementation of Handler.Callback */
260 @Override
261 public boolean handleMessage(Message msg) {
262 DisplayInfo info = null;
263 switch (msg.what) {
264 case SensorChannel.SENSOR_STATE_CHANGED:
265 info = mDisplayedSensors.get(msg.obj);
266 if (info != null) {
267 info.updateState();
269 break;
270 case SensorChannel.SENSOR_DISPLAY_MODIFIED:
271 info = mDisplayedSensors.get(msg.obj);
272 if (info != null) {
273 info.updateValue();
275 if (mSensorHandler != null) {
276 updateStatus(Integer.toString(mSensorHandler.getMsgSentCount()) + " events sent");
278 // Update the "actual rate" field if the value has changed
279 long ms = mSensorHandler.getActualUpdateMs();
280 if (ms != mLastActualUpdateMs) {
281 mLastActualUpdateMs = ms;
282 String hz = mLastActualUpdateMs <= 0 ? "--" :
283 Integer.toString((int) Math.ceil(1000. / ms));
284 mTextActualHz.setText(hz);
287 break;
288 case MSG_UPDATE_ACTUAL_HZ:
289 if (mSensorHandler != null) {
290 // Update the "actual rate" field if the value has changed
291 long ms = mSensorHandler.getActualUpdateMs();
292 if (ms != mLastActualUpdateMs) {
293 mLastActualUpdateMs = ms;
294 String hz = mLastActualUpdateMs <= 0 ? "--" :
295 Integer.toString((int) Math.ceil(1000. / ms));
296 mTextActualHz.setText(hz);
298 mUiHandler.sendEmptyMessageDelayed(MSG_UPDATE_ACTUAL_HZ, 1000 /*1s*/);
301 return true; // we consumed this message
304 private void updateStatus(String status) {
305 mTextStatus.setVisibility(status == null ? View.GONE : View.VISIBLE);
306 if (status != null) mTextStatus.setText(status);
309 private void updateError() {
310 ControllerBinder binder = getServiceBinder();
311 String error = binder == null ? "" : binder.getServiceError();
312 if (error == null) {
313 error = "";
316 mTextError.setVisibility(error.length() == 0 ? View.GONE : View.VISIBLE);
317 mTextError.setText(error);
320 private void updateSampleRate() {
321 String str = mTextTargetHz.getText().toString();
322 try {
323 int hz = Integer.parseInt(str.trim());
325 // Cap the value. 50 Hz is a reasonable max value for the emulator.
326 if (hz <= 0 || hz > 50) {
327 hz = 50;
330 if (hz != mTargetSampleRate) {
331 mTargetSampleRate = hz;
332 if (mSensorHandler != null) {
333 mSensorHandler.setUpdateTargetMs(hz <= 0 ? 0 : (int)(1000.0f / hz));
336 } catch (Exception ignore) {}