Java tutorial
/******************************************************************************** * Educational Online Test Delivery System * Copyright (c) 2015 American Institutes for Research * * Distributed under the AIR Open Source License, Version 1.0 * See accompanying file AIR-License-1_0.txt or at * http://www.smarterapp.org/documents/American_Institutes_for_Research_Open_Source_Software_License.pdf *********************************************************************************/ package com.air.mobilebrowser; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.HashMap; import java.util.List; import java.util.Locale; import org.json.JSONException; import org.json.JSONObject; import android.annotation.SuppressLint; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; import android.app.AlertDialog; import android.app.SearchManager; import android.bluetooth.BluetoothDevice; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Configuration; import android.graphics.Color; import android.media.AudioManager; import android.os.Bundle; import android.os.Handler; import android.preference.PreferenceManager; import android.speech.tts.TextToSpeech; import android.speech.tts.TextToSpeech.OnInitListener; import android.speech.tts.TextToSpeech.OnUtteranceCompletedListener; import android.support.v4.content.LocalBroadcastManager; import android.text.Editable; import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.style.ForegroundColorSpan; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnFocusChangeListener; import android.view.ViewParent; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; import android.webkit.WebSettings; import android.webkit.WebSettings.PluginState; import android.webkit.WebView; import android.widget.EditText; import android.widget.FrameLayout; import android.widget.ScrollView; import android.widget.TextView; import android.widget.Toast; import com.air.mobilebrowser.DeviceStatus.DeviceStatusChangeHandler; import com.air.mobilebrowser.jscmds.AIRRecorderClearFiles; import com.air.mobilebrowser.jscmds.AIRRecorderGetFile; import com.air.mobilebrowser.jscmds.AIRRecorderGetFileList; import com.air.mobilebrowser.jscmds.AIRRecorderInitialize; import com.air.mobilebrowser.jscmds.AIRRecorderPausePlayback; import com.air.mobilebrowser.jscmds.AIRRecorderResumePlayback; import com.air.mobilebrowser.jscmds.AIRRecorderStartCapture; import com.air.mobilebrowser.jscmds.AIRRecorderStartPlayback; import com.air.mobilebrowser.jscmds.AIRRecorderStopCapture; import com.air.mobilebrowser.jscmds.AIRRecorderStopPlayback; import com.air.mobilebrowser.jscmds.CheckSpeakStatus; import com.air.mobilebrowser.jscmds.ClearWebCache; import com.air.mobilebrowser.jscmds.ClearWebCookies; import com.air.mobilebrowser.jscmds.ExitApplication; import com.air.mobilebrowser.jscmds.GetProcesses; import com.air.mobilebrowser.jscmds.Initialize; import com.air.mobilebrowser.jscmds.JSCmd; import com.air.mobilebrowser.jscmds.JSCmdResponse; import com.air.mobilebrowser.jscmds.JSKeys; import com.air.mobilebrowser.jscmds.JSNTVCmds; import com.air.mobilebrowser.jscmds.JavascriptLog; import com.air.mobilebrowser.jscmds.OrientationLock; import com.air.mobilebrowser.jscmds.PauseSpeaking; import com.air.mobilebrowser.jscmds.RestartApplication; import com.air.mobilebrowser.jscmds.ResumeSpeaking; import com.air.mobilebrowser.jscmds.SetDefaultURL; import com.air.mobilebrowser.jscmds.SetMicMuted; import com.air.mobilebrowser.jscmds.SpeakText; import com.air.mobilebrowser.jscmds.StopSpeaking; import com.air.mobilebrowser.jscmds.TTSStatusRequest; import com.air.mobilebrowser.softkeyboard.KeyboardUtil; /** * Main activity component of the Secure Browser. Manages * the user interaction with the browser from a high level and * delegates work in response to requests from the web. */ @SuppressLint("SetJavaScriptEnabled") public class BrowserActivity extends Activity implements DeviceStatusChangeHandler, OnInitListener, OnUtteranceCompletedListener { private static final String TAG = "BroswerActivity"; //Logging Tag protected static final String _TAG_ = "AIR_SEC"; /* Our WebView instance */ protected WebView mWebView; /* Wrapper for device feature status */ protected DeviceStatus mDeviceStatus; /* Flag indicating we received a new intent to start the activity */ protected boolean mNewIntent = false; /* Flag indicating the browser has been previously pushed to background */ protected boolean mBeenBackgrounded = false; /* Receiver for intents from service */ private SBReceiver mSBReceiver; /* Flag indicating if already changing keyboard */ protected boolean mIsSelectingKeyboard = false; /* Flag to indicate if debug console is visible */ private boolean mIsDebugEnabled = false; /* Handler */ private Handler mHandler; /* Reference to system Audio Manager */ private AudioManager mAudioManager; /* Map of JS command to implementation */ private HashMap<String, JSCmd> mJSCommands; private TTSPlayer ttsPlayer; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ttsPlayer = new TTSPlayer(this); // Allow for out-of-band additions to thread queue (mainly for cleanup) mHandler = new Handler(); // Prevents user from taking screenshots. getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); // Load layout mWebView = new AIRWebView(this, this); mWebView.requestFocus(View.FOCUS_DOWN); setContentView(R.layout.activity_browser); FrameLayout layout = (FrameLayout) findViewById(R.id.sec_webview); layout.addView(((AIRWebView) mWebView).getLayout()); // Initialize device monitoring mDeviceStatus = new DeviceStatus(this, this); mDeviceStatus.registerReceivers(this); // By default, lock to landscape setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE); mDeviceStatus.lockedOrientation = "landscape"; // Configure the webview configureWebView(mWebView); // Configure Debug Console if (mIsDebugEnabled) { findViewById(R.id.slidingDrawer1).setVisibility(View.VISIBLE); findViewById(R.id.addressBarWrapper).setVisibility(View.VISIBLE); findViewById(R.id.goButton).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String url = ((EditText) findViewById(R.id.address_bar)).getText().toString(); mWebView.loadUrl(url); } }); } // Load the content SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); String url = preferences.getString("pref_default_url", getString(R.string.url_default_location)); // For testing, uncomment the following line to use a custom url: // Check for Internet connectivity if (mDeviceStatus.connectivity == DeviceStatus.CONNECTIVITY_CONNECTED) { mWebView.loadUrl(url); } else { mWebView.loadUrl("about:none"); } // Register BroadcastListener for service intents mSBReceiver = new SBReceiver(this); LocalBroadcastManager.getInstance(super.getApplicationContext()).registerReceiver(mSBReceiver, new IntentFilter(super.getResources().getString(R.string.intent_black_logtag))); LocalBroadcastManager.getInstance(super.getApplicationContext()).registerReceiver(mSBReceiver, new IntentFilter(super.getResources().getString(R.string.intent_micmutechanged))); LocalBroadcastManager.getInstance(super.getApplicationContext()).registerReceiver(mSBReceiver, new IntentFilter(super.getResources().getString(R.string.intent_keyboardchange))); // add receiver for bluetooth keyboard connection/disconnection events LocalBroadcastManager.getInstance(super.getApplicationContext()).registerReceiver(mSBReceiver, new IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED)); LocalBroadcastManager.getInstance(super.getApplicationContext()).registerReceiver(mSBReceiver, new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED)); IntentFilter testFilter = new IntentFilter(Intent.CATEGORY_HOME); super.getApplicationContext().registerReceiver(mSBReceiver, testFilter); // Get AudioManger mAudioManager = (AudioManager) super.getApplicationContext().getSystemService(Context.AUDIO_SERVICE); // Configure JS Command Processing configureJSCmdHandling(); // Begin monitoring for focus change. startService(new Intent(getApplicationContext(), ActivityWatchService.class)); } @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); //- Remove exit functionality, exit will be via javascript only. menu.add(0, 0, 0, "Exit").setIcon(android.R.drawable.ic_menu_close_clear_cancel) .setAlphabeticShortcut(SearchManager.MENU_KEY); /* Disabled Settings - Uncomment if needed (otherwise this will be removed later, along with the settings code) */ /* menu.add(0, 1, 0, R.string.menu_settings) .setIcon(android.R.drawable.ic_menu_preferences) .setIntent(new Intent(android.provider.Settings.ACTION_SETTINGS)); */ return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case 0: AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.alert_exit_title).setMessage(R.string.alert_exit_message); builder.setPositiveButton(R.string.alert_btn_exit, new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); // Get out of the dialog instance/execution and then perform cleanup mHandler.post(new Runnable() { @Override public void run() { cleanup(); } }); } }); builder.setNegativeButton(R.string.alert_btn_cancel, new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); builder.show(); return true; case 1: startActivity(new Intent(this, PreferencesActivity.class)); return true; } return super.onOptionsItemSelected(item); } @Override public void onBackPressed() { //Do nothing - prevents backing out of the activity. } @Override public void onConfigurationChanged(Configuration newConfig) { //Update the device status with the new orientation, and notify int orientation = newConfig.orientation; String orientationString = "none"; if (orientation == Configuration.ORIENTATION_PORTRAIT) { orientationString = "portrait"; } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) { orientationString = "landscape"; } else if (orientation == Configuration.ORIENTATION_UNDEFINED) { orientationString = "none"; } this.mDeviceStatus.orientation = orientationString; super.onConfigurationChanged(newConfig); handleOrientationChange(); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); mNewIntent = true; } @Override public void onResume() { super.onResume(); mWebView.onResume(); if (!validateHomePackage()) { Toast.makeText(this, "Please select Secure Browser as default to continue", Toast.LENGTH_LONG).show(); startActivity(new Intent(this, StartActivity.class)); cleanup(); } //If we are not resuming due to a new intent, notify that we have been backgrounded. // for Android 5.0 (Lollipop) or later versions, use a different flag to check if the browser has been backgrounded if (!mNewIntent || ((android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) && mBeenBackgrounded)) { executeAIRMobileFunction(JSNTVCmds.NTV_RETURN_FROM_BACKGROUND, null); } mNewIntent = false; mBeenBackgrounded = false; } @Override public void onPause() { ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); List<RunningTaskInfo> tasks = am.getRunningTasks(1); ComponentName topActivity = tasks.get(0).topActivity; String packageName = topActivity.getPackageName(); if (!packageName.equals(super.getPackageName()) && !packageName.equals("android")) { mBeenBackgrounded = true; executeAIRMobileFunction(JSNTVCmds.NTV_ENTER_BACKGROUND, null); } mWebView.onPause(); super.onPause(); } public void onStop() { mBeenBackgrounded = true; executeAIRMobileFunction(JSNTVCmds.NTV_ENTER_BACKGROUND, null); super.onStop(); } @Override public void onDestroy() { super.onDestroy(); LocalBroadcastManager.getInstance(super.getApplicationContext()).unregisterReceiver(mSBReceiver); mDeviceStatus.unregisterReceivers(this); ttsPlayer.destroy(); mWebView.loadUrl("about:blank"); clearHome(); } public WebView getWebView() { return mWebView; } /** * Configure a webview to use the activity as * its client, and update its settings with * the desired parameters for the activity. * @param webView the webview to configure. */ private void configureWebView(WebView webView) { webView.clearCache(true); webView.setWebViewClient(new SecureWebClient(this)); WebSettings settings = mWebView.getSettings(); settings.setBuiltInZoomControls(true); settings.setJavaScriptEnabled(true); // settings.setPluginState(PluginState.ON_DEMAND); settings.setPluginState(PluginState.ON); settings.setAllowFileAccess(true); settings.setAllowContentAccess(true); settings.setSaveFormData(false); settings.setSavePassword(false); webView.clearFormData(); settings.setDomStorageEnabled(true); String defaultUserAgent = settings.getUserAgentString(); StringBuilder sb = new StringBuilder(); sb.append(defaultUserAgent); sb.append(" SmarterSecureBrowser/1.0"); sb.append(" OS/"); sb.append(mDeviceStatus.operatingSystem); sb.append(" Version/"); sb.append(mDeviceStatus.operatingSystemVersion); sb.append(" Model/"); sb.append(mDeviceStatus.model); settings.setUserAgentString(sb.toString()); } /** * Configure JS Command Handling */ private void configureJSCmdHandling() { mJSCommands = new HashMap<String, JSCmd>(); addCommand(new CheckSpeakStatus(this, mDeviceStatus)); addCommand(new GetProcesses(this, mDeviceStatus)); addCommand(new Initialize(this, mDeviceStatus)); addCommand(new OrientationLock(this, mDeviceStatus)); addCommand(new SetDefaultURL(this, mDeviceStatus)); addCommand(new SetMicMuted(this, mDeviceStatus, mAudioManager)); addCommand(new SpeakText(this, mDeviceStatus, ttsPlayer)); addCommand(new PauseSpeaking(this, mDeviceStatus, ttsPlayer)); addCommand(new ResumeSpeaking(this, mDeviceStatus, ttsPlayer)); addCommand(new StopSpeaking(this, mDeviceStatus, ttsPlayer)); addCommand(new TTSStatusRequest(this, mDeviceStatus)); addCommand(new ExitApplication(this, mDeviceStatus)); addCommand(new RestartApplication(this, mDeviceStatus)); addCommand(new JavascriptLog(this, mDeviceStatus)); addCommand(new ClearWebCache(this, mDeviceStatus)); addCommand(new ClearWebCookies(this, mDeviceStatus)); addCommand(new AIRRecorderInitialize(this, mDeviceStatus)); addCommand(new AIRRecorderStartCapture(this, mDeviceStatus)); addCommand(new AIRRecorderStopCapture(this, mDeviceStatus)); addCommand(new AIRRecorderStartPlayback(this, mDeviceStatus)); addCommand(new AIRRecorderStopPlayback(this, mDeviceStatus)); addCommand(new AIRRecorderResumePlayback(this, mDeviceStatus)); addCommand(new AIRRecorderPausePlayback(this, mDeviceStatus)); addCommand(new AIRRecorderGetFileList(this, mDeviceStatus)); addCommand(new AIRRecorderGetFile(this, mDeviceStatus)); addCommand(new AIRRecorderClearFiles(this, mDeviceStatus)); } @SuppressLint("DefaultLocale") private void addCommand(JSCmd command) { mJSCommands.put(command.getCmd().toLowerCase(Locale.US), command); } /** * Clear the setting for default home. */ private void clearHome() { PackageManager pm = getPackageManager(); ComponentName fauxHomeComponent = new ComponentName(getApplicationContext(), FauxHome.class); ComponentName homeComponent = new ComponentName(getApplicationContext(), BrowserActivity.class); pm.setComponentEnabledSetting(fauxHomeComponent, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP); pm.setComponentEnabledSetting(homeComponent, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP); pm.setComponentEnabledSetting(fauxHomeComponent, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); pm.setComponentEnabledSetting(homeComponent, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); } /** * Cleanup everything that was changed. */ public void cleanup() { stopService(new Intent(getApplicationContext(), ActivityWatchService.class)); //clear home and exit PackageManager pm = getPackageManager(); ComponentName fauxHomeComponent = new ComponentName(getApplicationContext(), FauxHome.class); ComponentName homeComponent = new ComponentName(getApplicationContext(), BrowserActivity.class); pm.setComponentEnabledSetting(fauxHomeComponent, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); pm.setComponentEnabledSetting(homeComponent, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); mAudioManager.setMicrophoneMute(OrigSettings.getInstance().isMicMuted()); String curKeyboard = KeyboardUtil.getKeyboardPackage(BrowserActivity.this.getContentResolver()); if (!curKeyboard.equals(OrigSettings.getInstance().getKeyboard())) { KeyboardUtil.showInputChangedExitDialog(this, new DialogInterface.OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { finish(); } }); } else { finish(); } } /** * Determine if the application is set as the default * home. * @return true if the default home package is the secure browser, false * otherwise. */ public boolean validateHomePackage() { Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_HOME); PackageManager pm = getPackageManager(); final ResolveInfo mInfo = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY); String homePackage = mInfo.activityInfo.packageName; return homePackage.equals(getPackageName()); } private void handleOrientationChange() { final String ORIENTATION = "orientation"; JSONObject jsonToSend = new JSONObject(); try { jsonToSend.put(ORIENTATION, mDeviceStatus.orientation); } catch (JSONException e) { /* */ } executeAIRMobileFunction(JSNTVCmds.NTV_ON_ORIENTATION_CHANGE, jsonToSend.toString()); } private void handleUnsupportedRequest(JSONObject parameters) { String requestIdentifier = null; try { requestIdentifier = parameters.getString(JSKeys.REQUEST_IDENTIFIER); } catch (JSONException e) { /* */ } JSONObject jsonToSend = new JSONObject(); try { if (requestIdentifier != null) { jsonToSend.put(JSKeys.REQUEST_IDENTIFIER, requestIdentifier); } executeAIRMobileFunction(JSNTVCmds.NTV_ON_UNSUPPORTED_REQUEST, jsonToSend.toString()); } catch (JSONException e) { e.printStackTrace(); } } /** * Execute an AIRMobile javascript function. * eg. calling executeAIRMobileFunction("someFunction", "someParam"); * Executes AIRMobile.someFunction('someParam'); in the webview, and * logs the javascript to the console. * @param functionName the name of the AIRMobile function. * @param parameter the parameters to pass in the function. */ public void executeAIRMobileFunction(String functionName, String parameter) { String javascript = null; if (parameter != null) { javascript = "javascript:AIRMobile." + functionName + "('" + parameter + "')"; } else { javascript = "javascript:AIRMobile." + functionName + "()"; } logMessage("Executing Javascript", javascript); mWebView.loadUrl(javascript); } /** Logs an onscreen message for debugging. */ public void logMessage(final TextView consoleView, String message, String value, int color) { if (mIsDebugEnabled && consoleView != null) { consoleView.setOnFocusChangeListener(new OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { ViewParent parent = consoleView.getParent(); final ScrollView scroll = (ScrollView) parent; new Handler().postDelayed(new Runnable() { @Override public void run() { scroll.smoothScrollTo(0, consoleView.getMeasuredHeight() + 10); } }, 0); } }); Editable editable = consoleView.getEditableText(); SpannableString str = null; if (editable == null) { editable = new SpannableStringBuilder(); str = new SpannableString(message + ": " + value); str.setSpan(new ForegroundColorSpan(color), message.length() + 2, message.length() + 2 + value.length(), 0); } else { str = new SpannableString("\n" + message + ": " + value); str.setSpan(new ForegroundColorSpan(color), message.length() + 2, message.length() + 3 + value.length(), 0); } editable.append(str); consoleView.setText(editable, TextView.BufferType.EDITABLE); ViewParent parent = consoleView.getParent(); if (parent instanceof ScrollView) { final ScrollView scroll = (ScrollView) parent; new Handler().postDelayed(new Runnable() { @Override public void run() { scroll.smoothScrollTo(0, consoleView.getMeasuredHeight() + 10); } }, 1000); } } } /** * * @param message * @param value */ public void logMessage(String message, String value) { if (mIsDebugEnabled) { TextView consoleView = (TextView) findViewById(R.id.air_console_view); logMessage(consoleView, message, value, Color.BLUE); } } /** * Handle a request sent from the web page to do something. * @param request the name of the request * @param parameter optional parameter for the request when applicable */ protected void handleJSRequest(String request, String parameters) { Log.i(_TAG_, _TAG_ + " Received " + request); logMessage("Received URL", request); JSONObject jsonParameters = null; try { if (parameters != null) { jsonParameters = new JSONObject(URLDecoder.decode(parameters, "UTF-8")); } else { jsonParameters = new JSONObject(); } } catch (JSONException e) { /* Do nothing, we may not be getting actual parameters. */} catch (UnsupportedEncodingException e) { e.printStackTrace(); } /* Delegate the work */ if (mJSCommands.containsKey(request.toLowerCase(Locale.US))) { try { JSCmdResponse response = mJSCommands.get(request.toLowerCase(Locale.US)).handle(jsonParameters); if (response != null) { executeAIRMobileFunction(response.getNTVCmd(), response.getParameters()); } } catch (JSONException e) { Log.e(_TAG_, _TAG_ + " Error:", e); } } else { handleUnsupportedRequest(jsonParameters); Log.i(_TAG_, "Unknown JS Request " + request); } } /* - DeviceStatusChangeHandler Methods - */ @Override public void onConnectivityChanged(DeviceStatus deviceStatus) { JSONObject jsonObj = new JSONObject(); try { jsonObj.put(JSKeys.STATUS, deviceStatus.connectivity); } catch (JSONException e) { e.printStackTrace(); } executeAIRMobileFunction(JSNTVCmds.NTV_ON_CONNECTIVITY_CHANGE, jsonObj.toString()); if (deviceStatus.connectivity == DeviceStatus.CONNECTIVITY_DISCONNECTED) { handleNoInternet(); } } private void handleNoInternet() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.alert_exit_title).setMessage(R.string.alert_nointernet_message); builder.setPositiveButton(R.string.alert_btn_exit, new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); getHandler().post(new Runnable() { @Override public void run() { cleanup(); } }); } }); builder.show(); } @Override public void onTTSChanged(DeviceStatus deviceStatus) { } @Override public void onClipboardChanged(String clipText) { JSONObject jsonToSend = new JSONObject(); try { jsonToSend.put("contents", clipText); executeAIRMobileFunction(JSNTVCmds.NTV_ON_CLIPBOARD_CHANGE, jsonToSend.toString()); } catch (JSONException e) { /* */ } } public void onMicChanged() { boolean micMute = mAudioManager.isMicrophoneMute(); if (micMute != mDeviceStatus.micMuted) { JSONObject jsonToSend = new JSONObject(); // Make sure device status matches the actual mDeviceStatus.micMuted = mAudioManager.isMicrophoneMute(); try { jsonToSend.put(DeviceStatus.MICMUTED_KEY, mDeviceStatus.micMuted); executeAIRMobileFunction(JSNTVCmds.NTV_ON_MIC_MUTE_CHANGED, jsonToSend.toString()); } catch (JSONException e) { /* */ } } } public void onKeyboardChanged() { mDeviceStatus.keyboard = KeyboardUtil.getKeyboardPackage(super.getContentResolver()); JSONObject jsonObj = new JSONObject(); try { jsonObj.put(JSKeys.KEYBOARD, mDeviceStatus.keyboard); } catch (JSONException e) { e.printStackTrace(); } executeAIRMobileFunction(JSNTVCmds.NTV_ON_KEYBOARD_CHANGED, jsonObj.toString()); } public void onBlackLogTag() { executeAIRMobileFunction(JSNTVCmds.NTV_MINI_APP_LAUNCHED, null); } @SuppressWarnings("deprecation") @Override public void onInit(int status) { if (status == TextToSpeech.SUCCESS) { int result = ttsPlayer.getTextToSpeech().setLanguage(Locale.US); if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) { Log.e(TAG, "Language data missing or not supported"); mDeviceStatus.ttsEngineStatus = DeviceStatus.TTS_ENGINE_STATUS_UNAVAILABLE; } else { mDeviceStatus.ttsEngineStatus = DeviceStatus.TTS_ENGINE_STATUS_IDLE; } } else { Log.e(TAG, "Unable to initialize TextToSpeech (status: " + status + ")"); mDeviceStatus.ttsEngineStatus = DeviceStatus.TTS_ENGINE_STATUS_UNAVAILABLE; } // Notification of completion comes in on different thread, currently // UI updates necessary in executeAIRMobileFunction super.runOnUiThread(new Runnable() { @Override public void run() { JSONObject jsonToSend = new JSONObject(); try { jsonToSend.put(JSKeys.TTS_ENABLED, mDeviceStatus.ttsEnabled); jsonToSend.put(JSKeys.TTS_ENGINE_STATUS, mDeviceStatus.ttsEngineStatus); executeAIRMobileFunction(JSNTVCmds.NTV_ON_TTS_ENABLED, jsonToSend.toString()); } catch (JSONException e) { e.printStackTrace(); } } }); } @Override public void onUtteranceCompleted(String requestIdentifier) { final JSONObject jsonToSend = new JSONObject(); try { jsonToSend.put("enabled", mDeviceStatus.ttsEnabled); mDeviceStatus.ttsEngineStatus = DeviceStatus.TTS_ENGINE_STATUS_IDLE; jsonToSend.put(JSKeys.TTS_ENGINE_STATUS, mDeviceStatus.ttsEngineStatus); // Notification of completion comes in on different thread, currently // UI updates necessary in executeAIRMobileFunction super.runOnUiThread(new Runnable() { @Override public void run() { executeAIRMobileFunction(JSNTVCmds.NTV_ON_TTS_ENABLED, jsonToSend.toString()); } }); } catch (JSONException e) { /* */ } } /** * @return the mHandler */ public Handler getHandler() { return mHandler; } public boolean isDebugEnabled() { return mIsDebugEnabled; } }