/shell/src/com/google/marvin/shell/AuditoryWidgets.java

http://eyes-free.googlecode.com/ · Java · 401 lines · 313 code · 36 blank · 52 comment · 83 complexity · f07965c81afe86d48b7f954674240c37 MD5 · raw file

  1. /*
  2. * Copyright (C) 2010 Google Inc.
  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. package com.google.marvin.shell;
  17. import android.bluetooth.BluetoothAdapter;
  18. import android.content.ActivityNotFoundException;
  19. import android.content.BroadcastReceiver;
  20. import android.content.ContentResolver;
  21. import android.content.Context;
  22. import android.content.Intent;
  23. import android.content.IntentFilter;
  24. import android.net.ConnectivityManager;
  25. import android.net.NetworkInfo;
  26. import android.net.Uri;
  27. import android.net.wifi.WifiInfo;
  28. import android.net.wifi.WifiManager;
  29. import android.os.BatteryManager;
  30. import android.provider.Settings.SettingNotFoundException;
  31. import android.provider.Settings.System;
  32. import android.speech.RecognizerIntent;
  33. import android.speech.tts.TextToSpeech;
  34. import android.telephony.PhoneStateListener;
  35. import android.telephony.ServiceState;
  36. import android.telephony.TelephonyManager;
  37. import java.lang.reflect.Method;
  38. import java.text.SimpleDateFormat;
  39. import java.util.Calendar;
  40. import java.util.HashMap;
  41. // Most of the logic for determining strength levels is based on the code here:
  42. // http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob_plain;f=services/java/com/android/server/status/StatusBarPolicy.java
  43. /**
  44. * Collection of one shot speech widgets for the home screen
  45. *
  46. * @author clchen@google.com (Charles L. Chen)
  47. * @author credo@google.com (Tim Credo)
  48. */
  49. public class AuditoryWidgets {
  50. private TextToSpeech tts;
  51. private MarvinShell parent;
  52. private Guide guide;
  53. private boolean useGpsThisTime;
  54. private int voiceSignalStrength;
  55. private int callState = TelephonyManager.CALL_STATE_IDLE;
  56. /**
  57. * Map user-facing widget descriptions to the strings used to indicate them
  58. * in XML.
  59. */
  60. public HashMap<String, String> descriptionToWidget;
  61. public AuditoryWidgets(TextToSpeech theTts, MarvinShell shell) {
  62. tts = theTts;
  63. parent = shell;
  64. useGpsThisTime = true;
  65. voiceSignalStrength = 0;
  66. TelephonyManager tm = (TelephonyManager) parent.getSystemService(Context.TELEPHONY_SERVICE);
  67. tm.listen(new PhoneStateListener() {
  68. private boolean inService = true;
  69. @Override
  70. public void onServiceStateChanged(ServiceState service) {
  71. if (service.getState() != ServiceState.STATE_IN_SERVICE) {
  72. inService = false;
  73. } else {
  74. inService = true;
  75. }
  76. }
  77. @Override
  78. public void onSignalStrengthChanged(int asu) {
  79. if ((asu == -1) || !inService) {
  80. voiceSignalStrength = -1;
  81. } else if (asu <= 0 || asu == 99) {
  82. voiceSignalStrength = 0;
  83. } else if (asu >= 16) {
  84. voiceSignalStrength = 4;
  85. } else if (asu >= 8) {
  86. voiceSignalStrength = 3;
  87. } else if (asu >= 4) {
  88. voiceSignalStrength = 2;
  89. } else {
  90. voiceSignalStrength = 1;
  91. }
  92. }
  93. @Override
  94. public void onCallStateChanged(int state, String incomingNumber) {
  95. callState = state;
  96. }
  97. },
  98. PhoneStateListener.LISTEN_SIGNAL_STRENGTH | PhoneStateListener.LISTEN_SERVICE_STATE
  99. | PhoneStateListener.LISTEN_CALL_STATE);
  100. descriptionToWidget = new HashMap<String, String>();
  101. descriptionToWidget.put(parent.getString(R.string.applications), "APPLAUNCHER");
  102. descriptionToWidget.put(parent.getString(R.string.autosync_toggle), "TOGGLE_AUTOSYNC");
  103. descriptionToWidget.put(parent.getString(R.string.battery), "BATTERY");
  104. descriptionToWidget.put(parent.getString(R.string.bluetooth_toggle), "TOGGLE_BLUETOOTH");
  105. descriptionToWidget.put(parent.getString(R.string.location), "LOCATION");
  106. descriptionToWidget.put(parent.getString(R.string.search_widget), "VOICE_SEARCH");
  107. descriptionToWidget.put(parent.getString(R.string.signal), "CONNECTIVITY");
  108. descriptionToWidget.put(parent.getString(R.string.time), "TIME_DATE");
  109. descriptionToWidget.put(parent.getString(R.string.voicemail), "VOICEMAIL");
  110. descriptionToWidget.put(parent.getString(R.string.wifi_toggle), "TOGGLE_WIFI");
  111. descriptionToWidget.put(
  112. parent.getString(R.string.open_notifications), "OPEN_NOTIFICATIONS");
  113. descriptionToWidget.put(
  114. parent.getString(R.string.android_launcher), "ANDROID_LAUNCHER");
  115. }
  116. public void shutdown() {
  117. if (guide != null) {
  118. guide.shutdown();
  119. }
  120. try {
  121. TelephonyManager tm = (TelephonyManager) parent.getSystemService(
  122. Context.TELEPHONY_SERVICE);
  123. tm.listen(new PhoneStateListener() {
  124. }, PhoneStateListener.LISTEN_NONE);
  125. } catch (RuntimeException e) {
  126. // There will be a runtime exception if shutdown is being forced by
  127. // the
  128. // user.
  129. // Ignore the error here as shutdown will be called a second time
  130. // when the
  131. // shell is destroyed.
  132. }
  133. }
  134. /**
  135. * Run the widget code corresponding to the given string.
  136. */
  137. public void runWidget(String widgetName) {
  138. if (widgetName.equals("TIME_DATE")) {
  139. announceTime();
  140. } else if (widgetName.equals("BATTERY")) {
  141. announceBattery();
  142. } else if (widgetName.equals("VOICEMAIL")) {
  143. tts.playEarcon(parent.getString(R.string.earcon_tick), TextToSpeech.QUEUE_FLUSH, null);
  144. callVoiceMail();
  145. } else if (widgetName.equals("LOCATION")) {
  146. tts.playEarcon(parent.getString(R.string.earcon_tick), TextToSpeech.QUEUE_FLUSH, null);
  147. speakLocation();
  148. } else if (widgetName.equals("CONNECTIVITY")) {
  149. announceConnectivity();
  150. } else if (widgetName.equals("APPLAUNCHER")) {
  151. parent.switchToAppChooserView();
  152. } else if (widgetName.equals("VOICE_SEARCH")) {
  153. launchVoiceSearch();
  154. } else if (widgetName.equals("TOGGLE_BLUETOOTH")) {
  155. toggleBluetooth();
  156. } else if (widgetName.equals("TOGGLE_AUTOSYNC")) {
  157. toggleAutosync();
  158. } else if (widgetName.equals("TOGGLE_WIFI")) {
  159. toggleWifi();
  160. } else if (widgetName.equals("OPEN_NOTIFICATIONS")) {
  161. openNotifications();
  162. } else if (widgetName.equals("ANDROID_LAUNCHER")) {
  163. launchDefaultHomeScreen();
  164. }
  165. }
  166. private void speakDataNetworkInfo() {
  167. String info = parent.getString(R.string.no_data_network);
  168. ConnectivityManager cManager = (ConnectivityManager) parent.getSystemService(
  169. Context.CONNECTIVITY_SERVICE);
  170. NetworkInfo networkInfo = cManager.getActiveNetworkInfo();
  171. if (networkInfo != null) {
  172. if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
  173. info = parent.getString(R.string.mobile_data_network);
  174. TelephonyManager tm = (TelephonyManager) parent.getSystemService(
  175. Context.TELEPHONY_SERVICE);
  176. if (tm.getNetworkType() == TelephonyManager.NETWORK_TYPE_UMTS) {
  177. info = parent.getString(R.string.threeg_data_network);
  178. } else if (tm.getNetworkType() == TelephonyManager.NETWORK_TYPE_EDGE) {
  179. info = parent.getString(R.string.edge_data_network);
  180. }
  181. } else if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
  182. WifiManager wManager = (WifiManager) parent.getSystemService(Context.WIFI_SERVICE);
  183. WifiInfo wInfo = wManager.getConnectionInfo();
  184. int wifiSignalStrength = WifiManager.calculateSignalLevel(wInfo.getRssi(), 4);
  185. info = parent.getString(R.string.wifi) + wInfo.getSSID() + " "
  186. + parent.getString(R.string.bars, wifiSignalStrength);
  187. }
  188. }
  189. tts.speak(info, TextToSpeech.QUEUE_ADD, null);
  190. }
  191. private void speakVoiceNetworkInfo() {
  192. TelephonyManager tm = (TelephonyManager) parent.getSystemService(Context.TELEPHONY_SERVICE);
  193. String voiceNetworkOperator = tm.getNetworkOperatorName();
  194. String voiceNetworkStrength = parent.getString(R.string.bars, voiceSignalStrength);
  195. if (voiceSignalStrength == -1) {
  196. voiceNetworkStrength = "";
  197. }
  198. String voiceNetworkInfo = voiceNetworkOperator + ", " + voiceNetworkStrength;
  199. tts.speak(voiceNetworkInfo, TextToSpeech.QUEUE_ADD, null);
  200. }
  201. public void announceConnectivity() {
  202. String bluetooth = "";
  203. String gps = "";
  204. try {
  205. ContentResolver cr = parent.getContentResolver();
  206. if (System.getInt(cr, System.BLUETOOTH_ON) == 1) {
  207. bluetooth = parent.getString(R.string.bluetooth);
  208. }
  209. String locationProviders = System.getString(cr, System.LOCATION_PROVIDERS_ALLOWED);
  210. if ((locationProviders.length() > 0) && locationProviders.contains("gps")) {
  211. gps = parent.getString(R.string.gps);
  212. }
  213. } catch (SettingNotFoundException e) {
  214. e.printStackTrace();
  215. }
  216. tts.stop();
  217. speakVoiceNetworkInfo();
  218. speakDataNetworkInfo();
  219. tts.speak(bluetooth, TextToSpeech.QUEUE_ADD, null);
  220. tts.speak(gps, TextToSpeech.QUEUE_ADD, null);
  221. }
  222. public void announceBattery() {
  223. BroadcastReceiver battReceiver = new BroadcastReceiver() {
  224. @Override
  225. public void onReceive(Context context, Intent intent) {
  226. context.unregisterReceiver(this);
  227. int rawlevel = intent.getIntExtra("level", -1);
  228. int scale = intent.getIntExtra("scale", -1);
  229. int status = intent.getIntExtra("status", -1);
  230. String message = "";
  231. if (rawlevel >= 0 && scale > 0) {
  232. int batteryLevel = (rawlevel * 100) / scale;
  233. message = Integer.toString(batteryLevel) + "%";
  234. // tts.speak(Integer.toString(batteryLevel), 0, null);
  235. // tts.speak("%", 1, null);
  236. }
  237. if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
  238. // parent.tts.playEarcon(TTSEarcon.SILENCE, 1, null);
  239. // tts.speak(parent.getString(R.string.charging), 1, null);
  240. message = message + " " + parent.getString(R.string.charging);
  241. }
  242. tts.speak(message, TextToSpeech.QUEUE_FLUSH, null);
  243. }
  244. };
  245. IntentFilter battFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
  246. parent.registerReceiver(battReceiver, battFilter);
  247. }
  248. public void announceTime() {
  249. Calendar cal = Calendar.getInstance();
  250. int day = cal.get(Calendar.DAY_OF_MONTH);
  251. SimpleDateFormat monthFormat = new SimpleDateFormat("MMMM");
  252. String monthStr = monthFormat.format(cal.getTime());
  253. int hour = cal.get(Calendar.HOUR_OF_DAY);
  254. int minutes = cal.get(Calendar.MINUTE);
  255. String ampm = "";
  256. if (hour == 0) {
  257. ampm = parent.getString(R.string.midnight);
  258. hour = 12;
  259. } else if (hour == 12) {
  260. ampm = parent.getString(R.string.noon);
  261. } else if (hour > 12) {
  262. hour = hour - 12;
  263. ampm = parent.getString(R.string.pm);
  264. } else {
  265. ampm = parent.getString(R.string.am);
  266. }
  267. String timeStr = Integer.toString(hour) + " " + Integer.toString(minutes) + " " + ampm;
  268. tts.speak(timeStr + " " + monthStr + " " + Integer.toString(day), TextToSpeech.QUEUE_FLUSH,
  269. null);
  270. }
  271. public void callVoiceMail() {
  272. Uri phoneNumberURI = Uri.parse("voicemail:");
  273. Intent intent = new Intent(Intent.ACTION_CALL, phoneNumberURI);
  274. parent.startActivity(intent);
  275. }
  276. public void speakLocation() {
  277. guide = new Guide(parent);
  278. guide.speakLocation(useGpsThisTime);
  279. useGpsThisTime = !useGpsThisTime;
  280. }
  281. public void launchVoiceSearch() {
  282. Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
  283. intent.putExtra(
  284. RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_WEB_SEARCH);
  285. try {
  286. parent.startActivityForResult(intent, MarvinShell.VOICE_RECO_CODE);
  287. } catch (ActivityNotFoundException anf) {
  288. parent.tts.speak(parent.getString(R.string.search_not_available),
  289. TextToSpeech.QUEUE_FLUSH, null);
  290. }
  291. }
  292. public void launchDefaultHomeScreen() {
  293. parent.startActivity(parent.getSystemHomeIntent());
  294. }
  295. public int getCallState() {
  296. return callState;
  297. }
  298. /**
  299. * Toggles the state of the BluetoothAdapter.
  300. */
  301. public void toggleBluetooth() {
  302. BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
  303. if (adapter.isEnabled()) {
  304. if (adapter.disable()) {
  305. parent.tts.speak(parent.getString(R.string.bluetooth_turning_off),
  306. TextToSpeech.QUEUE_FLUSH, null);
  307. }
  308. } else {
  309. if (adapter.enable()) {
  310. parent.tts.speak(parent.getString(R.string.bluetooth_turning_on),
  311. TextToSpeech.QUEUE_FLUSH, null);
  312. }
  313. }
  314. }
  315. /**
  316. * Toggles the state of the WifiManager.
  317. */
  318. public void toggleWifi() {
  319. WifiManager manager = (WifiManager) parent.getSystemService(Context.WIFI_SERVICE);
  320. if (manager.isWifiEnabled()) {
  321. if (manager.setWifiEnabled(false)) {
  322. parent.tts.speak(
  323. parent.getString(R.string.wifi_off), TextToSpeech.QUEUE_FLUSH, null);
  324. }
  325. } else {
  326. if (manager.setWifiEnabled(true)) {
  327. parent.tts.speak(
  328. parent.getString(R.string.wifi_on), TextToSpeech.QUEUE_FLUSH, null);
  329. }
  330. }
  331. }
  332. /**
  333. * Toggles sync settings for apps. that request data in the background.
  334. */
  335. public void toggleAutosync() {
  336. ConnectivityManager manager = (ConnectivityManager) parent.getSystemService(
  337. Context.CONNECTIVITY_SERVICE);
  338. boolean backgroundData = manager.getBackgroundDataSetting();
  339. if (ContentResolver.getMasterSyncAutomatically()) {
  340. ContentResolver.setMasterSyncAutomatically(false);
  341. parent.tts.speak(
  342. parent.getString(R.string.autosync_off), TextToSpeech.QUEUE_FLUSH, null);
  343. } else {
  344. ContentResolver.setMasterSyncAutomatically(true);
  345. parent.tts.speak(
  346. parent.getString(R.string.autosync_on), TextToSpeech.QUEUE_FLUSH, null);
  347. if (!backgroundData) {
  348. parent.tts.speak(parent.getString(R.string.background_data_warning),
  349. TextToSpeech.QUEUE_ADD, null);
  350. }
  351. }
  352. }
  353. /**
  354. * Opens the notifications status bar.
  355. */
  356. public void openNotifications() {
  357. try {
  358. Object service = parent.getSystemService("statusbar");
  359. Class<?> statusBarManager = Class.forName("android.app.StatusBarManager");
  360. Method expand = statusBarManager.getMethod("expand");
  361. expand.invoke(service);
  362. } catch (Exception e) {
  363. }
  364. }
  365. }