AccessibilityEvents not being caught by service on Activity start - android

I'm trying to have my app announce some information to my custom AccessibilityService when the user starts an Activity. I have a TextView that calls requestFocus() when the activity starts, and then I send an AccessibilityEvent to have the AccessibilityService read the TextView's content description. I've isolated the problem into a small application.
Here's the main Activity:
package com.example.ttstest;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
View v = findViewById(R.id.textView1);
v.requestFocus();
v.sendAccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT);
}
}
The layout file:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.example.ttstest.MainActivity" >
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="true"
android:focusableInTouchMode="true"
android:contentDescription="Secondarily focused text view"
android:text="#string/hello_world" />
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/textView2"
android:layout_marginLeft="54dp"
android:layout_marginTop="145dp"
android:layout_toRightOf="#+id/textView2"
android:contentDescription="Initially focused text view"
android:focusable="true"
android:focusableInTouchMode="true"
android:text="Initially focused text view" />
</RelativeLayout>
And the AccessibilityService:
package com.example.ttstest;
import android.accessibilityservice.AccessibilityService;
import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeech.OnInitListener;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
public class TextToSpeechService extends AccessibilityService {
private static TextToSpeech textToSpeech = null;
private static boolean ttsReady = false;
#Override
protected void onServiceConnected() {
super.onServiceConnected();
Log.e("TextToSpeechService", "Got to onServiceConnected()");
textToSpeech = new TextToSpeech(this.getApplicationContext(), new OnInitListener() {
#Override
public void onInit(int status) {
if(status == TextToSpeech.SUCCESS) {
ttsReady = true;
}
}
});
}
#Override
public void onAccessibilityEvent(AccessibilityEvent event) {
Log.e("TextToSpeechService", "Entering onAccessibilityEvent().");
Log.e("TextToSpeechService", "Event type: " + event.getEventType() + ", from class " + event.getClassName());
if(event.getContentDescription() != null) {
Log.e("TextToSpeechService", "" + event.getContentDescription());
}
if(textToSpeech != null && ttsReady == true) {
if(event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED) {
CharSequence contentDescription = event.getContentDescription();
if(contentDescription != null) {
String say = contentDescription.toString();
textToSpeech.speak(say, TextToSpeech.QUEUE_FLUSH, null);
}
} else if (event.getEventType() == AccessibilityEvent.TYPE_ANNOUNCEMENT) {
CharSequence contentDescription = event.getContentDescription();
if(contentDescription != null) {
textToSpeech.speak(event.getContentDescription().toString(), TextToSpeech.QUEUE_FLUSH, null);
}
}
}
Log.e("TextToSpeechService", "Exiting onAccessibilityEvent().");
}
#Override
public void onInterrupt() {
Log.e("TextToSpeechService", "Entering onInterrupt()");
if(textToSpeech != null && ttsReady == true) {
textToSpeech.stop();
}
}
}
This has been added to my AndroidManifest.xml in the appropriate location:
<service android:name="com.example.ttstest.TextToSpeechService"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE" >
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
<meta-data android:name="android.accessibilityservice"
android:resource="#xml/accessibilityservice"/>
</service>
My accessibilityservice.xml settings:
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeAllMask"
android:notificationTimeout="100"
android:accessibilityFeedbackType="feedbackSpoken"
android:accessibilityFlags="flagDefault"
android:canRetrieveWindowContent="true"
android:packageNames="com.example.ttstest"/>
And finally, the problem. When I first start the application, neither the TextView gaining focus from requestFocus() or the call to sendAccessibilityEvent() actually send anything to the AccessibilityService. If I tab through the TextViews by attaching a physical keyboard, the focus events are received. I have made sure to turn on the AccessibilityService in the settings, and I have proof from the application I made this example from that the AccessibilityService is enabled when requestFocus() and sendAccessibilityEvent() are called. This doesn't help. It seems like when an Activity is first started, neither of these methods send anything to the AccessibilityService. I've also tried calling announceForAccessibility() with similar results.
Am I doing this wrong? How can I fix it, or at least get around it? Specifically, I want to send an event to my AccessibilityService when an Activity first starts.
More information: I have tried moving the requestFocus() and sendAccessibilityEvent() calls to onStart() and onWindowFocusChanged(); neither of these work either.

I may be mistaken but the "UI" isn't ready until onResume() is called so perhaps that is the issue?

Related

Call network api just as activity is finishing

I have a preference screen in my application and I want to save the user preferences in the server, but I don't want any update button in the settings, I was hoping to make this update api call when the activity is finishing, maybe I can call the api in onPause(), the problem is, if the api takes more time than expected to return then I will have a network call running without an activity, which in my general knowledge is a memory leak. If I try to have this network call in the main thread and the call takes too long I will get an ANR.
How can I achieve this behaviour in my application. I am using retrofit2 with rxjava2 to make api calls.
You can create an AsyncTask for the Networking since the doInBackground() creates a background thread which you need to avoid networking on MainThread. Also, Activity stop doesn't stop the AsyncTask.
If you need a response (for example a Toast to inform user that preferences have successfully saved) use IntentService, otherwise Service. For detailed description of the differences see: Service vs IntentService.
For the implementation (with a good example) take a look at:
https://developer.android.com/guide/components/services and
https://developer.android.com/guide/components/broadcasts (for implementing broadcast receiver in order to process the result)
Here is a simple app. In Main Activity we go to SecondActivity. There we set some values, start a service to process them and finish the activity. When everything is ready, the MainActivity is updated automatically.
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.sytes.csongi.servicetest">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".SecondActivity">
</activity>
<service
android:name="services.MyIntentService"
android:exported="false"
>
</service>
</application>
</manifest>
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/main_result_txt"
android:text="Test"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/main_open_intent_btn"
android:text="start"
android:layout_gravity="center"/>
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
activity_second.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".SecondActivity">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/second_edit_01_txt"
android:hint="Enter some text here"/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/second_edit_02_txt"
android:hint="another text here"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/second_start_process_btn"
android:text="start processing"
android:layout_gravity="center"/>
</LinearLayout>
MainActivity.java:
package net.sytes.csongi.servicetest;
import android.content.*;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Button;
import android.widget.TextView;
import butterknife.BindView;
import butterknife.ButterKnife;
import services.MyIntentService;
public class MainActivity extends AppCompatActivity {
private static final String TAG=MainActivity.class.getSimpleName();
private BroadcastReceiver mBroadcastReceiver;
private IntentFilter mIntentFilter;
#BindView(R.id.main_open_intent_btn)
Button mOpenIntentBtn;
#BindView(R.id.main_result_txt)
TextView mResultTxt;
public static final String ACTION_MAIN_ACTIVITY = "ACTION_MAIN_ACTIVITY";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
mIntentFilter=new IntentFilter();
mIntentFilter.addAction(ACTION_MAIN_ACTIVITY);
mBroadcastReceiver=new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "onReceive:::: called");
String action=intent.getAction();
if(action!=null&& ACTION_MAIN_ACTIVITY.equals(action)){
processReceivedIntent(intent);
}
}
};
registerReceiver(mBroadcastReceiver,mIntentFilter);
mOpenIntentBtn.setOnClickListener(v->
{
Intent startSecondActivity=new Intent(this,SecondActivity.class);
startActivity(startSecondActivity);
});
}
#Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy:::: called, unregistering Receiver");
unregisterReceiver(mBroadcastReceiver);
}
private void processReceivedIntent(Intent intent) {
Log.d(TAG, "processReceivedIntent:::: called");
StringBuilder builder=new StringBuilder("The values recieved: \n");
String returnedString=intent.getStringExtra(MyIntentService.EXTRA_TO_PROCESS);
builder.append(returnedString);
mResultTxt.setText(builder.toString());
}
}
SecondActivity.java:
package net.sytes.csongi.servicetest;
import android.content.ContentValues;
import android.os.Bundle;
import android.support.annotation.StringDef;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.Button;
import android.widget.EditText;
import butterknife.BindView;
import butterknife.ButterKnife;
import services.MyIntentService;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import static net.sytes.csongi.servicetest.SecondActivity.ValuesToSend.EDIT_TEXT_ONE;
import static net.sytes.csongi.servicetest.SecondActivity.ValuesToSend.EDIT_TEXT_TWO;
public class SecondActivity extends AppCompatActivity {
private static final String TAG=SecondActivity.class.getSimpleName();
#BindView(R.id.second_edit_01_txt)
EditText mSecondEditOne;
#BindView(R.id.second_edit_02_txt)
EditText mSecondEditTwo;
#BindView(R.id.second_start_process_btn)
Button mStartProcess;
#Retention(RetentionPolicy.SOURCE)
#StringDef({EDIT_TEXT_ONE,
EDIT_TEXT_TWO})
public #interface ValuesToSend {
/**
* edit text key for textField_01
*/
String EDIT_TEXT_ONE = "EDIT_TEXT_ONE";
/**
* edit text key for textField_02;
*/
String EDIT_TEXT_TWO = "EDIT_TEXT_TWO";
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
ButterKnife.bind(this);
mStartProcess.setOnClickListener(v -> {
startProcess();
});
}
private void startProcess() {
Log.d(TAG, "startProcess:::: called");
finish();
}
#Override
protected void onStop() {
super.onStop();
Log.d(TAG, "onStop:::: called");
ContentValues valuesToSend=new ContentValues();
valuesToSend.put(EDIT_TEXT_ONE,mSecondEditOne.getText().toString());
valuesToSend.put(EDIT_TEXT_TWO,mSecondEditTwo.getText().toString());
Log.d(TAG, "onStop:::: contentValues size="+valuesToSend.size());
Bundle toSend=new Bundle();
toSend.putParcelable(MyIntentService.BUNDLE_CONTENT_VALUES_KEY,valuesToSend);
MyIntentService.startActionProcess(this,toSend);
}
}
MyIntentService.java:
package services;
import android.app.IntentService;
import android.content.ContentValues;
import android.content.Intent;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import net.sytes.csongi.servicetest.MainActivity;
import java.util.Iterator;
import java.util.Set;
/**
* An {#link IntentService} subclass for handling asynchronous task requests in
* a service on a separate handler thread.
* <p>
* helper methods.
*/
public class MyIntentService extends IntentService {
private static final String TAG=MyIntentService.class.getSimpleName();
// IntentService can perform, e.g. ACTION_FETCH_NEW_ITEMS
public static final String ACTION_PROCESS = "services.action.PROCESS";
public static final String BUNDLE_TO_PROCESS="BUNDLE_TO_PROCESS";
public static final String BUNDLE_CONTENT_VALUES_KEY = "BUNDLE_CONTENT_VALUES_KEY";
public static final String EXTRA_TO_PROCESS = "EXTRA_TO_PROCESS";
public MyIntentService() {
super("MyIntentService");
Log.d(TAG, "MyIntentService:::: instantiated");
}
/**
* Starts this service to perform action Foo with the given parameters. If
* the service is already performing a task this action will be queued.
*
* #see IntentService
*/
public static void startActionProcess(Context context, Bundle bundle) {
Log.d(TAG, "startActionProcess:::: called");
Intent intent = new Intent(context, MyIntentService.class);
intent.setAction(ACTION_PROCESS);
intent.putExtra(BUNDLE_TO_PROCESS, bundle);
context.startService(intent);
}
#Override
protected void onHandleIntent(Intent intent) {
Log.d(TAG, "onHandleIntent:::: called");
if (intent != null) {
final String action = intent.getAction();
if (ACTION_PROCESS.equals(action)) {
final Bundle bundleToProcess = intent.getBundleExtra(BUNDLE_TO_PROCESS);
handleAction(bundleToProcess);
}
}
}
private void handleAction(Bundle bundleToProcess) {
// here we run the long process
Log.d(TAG, "handleAction:::: called");
ContentValues contentValues= bundleToProcess.getParcelable(BUNDLE_CONTENT_VALUES_KEY);
StringBuilder builder=new StringBuilder("Processed values are:\n");
int numberOfValues=contentValues.size();
Set<String> valuesKeySet=contentValues.keySet();
Iterator<String> iterator=valuesKeySet.iterator();
while(iterator.hasNext()){
builder.append(contentValues.getAsString(iterator.next())+"\n");
try{ // simulating latency
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// send result to appropriate activity
Intent resultIntent=new Intent();
resultIntent.setAction(MainActivity.ACTION_MAIN_ACTIVITY);
resultIntent.putExtra(EXTRA_TO_PROCESS,builder.toString());
sendBroadcast(resultIntent);
}
}
Hope I could help you.

Android: Issuing search method too frequently causing crashes

I have a search bar, a search button (as i just converted to using onKeyPress and haven't removed it yet), and a TextView.
It works well, except that each key press issues a new call to Search(), and the old call doesn't stop running. If i type too quickly or for too long, the app crashes. How do I better manage my threads or quit prior Search() executions when onKeyPress() fires?
Thanks!
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="corp.dtc.tel" >
<application
android:allowBackup="true"
android:icon="#mipmap/tel_ico"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".TEL_Main_Activity"
android:label="#string/app_name"
android:theme="#style/Theme.AppCompat.Light.DarkActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
MainActivity.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingTop="10dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="10dp"
android:paddingLeft="10dp"
android:paddingRight="10dp" >
<EditText
android:id="#+id/search_box"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:hint="Enter Here"
android:inputType="text"
android:textSize="12sp"
android:layout_marginLeft="5dp"
android:layout_weight="1" />
<Button
android:id="#+id/search_button"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="Search..."
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:onClick="Search"/>
</LinearLayout>
<TextView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:hint="List of Numbers will be here"
android:id="#+id/list_view"
android:maxLines="50"
android:scrollbars="vertical"
android:freezesText="true" />
</LinearLayout>
MainActivity.java
package corp.dtc.tel;
import android.content.Intent;
import android.graphics.Typeface;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.text.method.ScrollingMovementMethod;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.io.IOException;
public class TEL_Main_Activity extends ActionBarActivity {
TextView textView;
EditText editText;
Button button;
Employee[] list;
Employee[] employees;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActionBar actionBar = getSupportActionBar();
actionBar.setLogo(R.mipmap.tel_ico);
actionBar.setDisplayUseLogoEnabled(true);
actionBar.setDisplayShowHomeEnabled(true);
LoadArray la = new LoadArray();
try {
employees = la.LoadArray(this, R.raw.droid);
} catch (IOException e) {}
setContentView(R.layout.activity_tel_main);
textView = (TextView) findViewById(R.id.list_view);
textView.setHorizontallyScrolling(true);
textView.setMovementMethod(new ScrollingMovementMethod());
textView.setTypeface(Typeface.MONOSPACE);
button = (Button) findViewById(R.id.search_button);
editText = (EditText) findViewById(R.id.search_box);
editText.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
Search(findViewById(R.id.layout));
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
#Override
public void onResume() {
super.onResume();
try {
//check if any view exists on current view
Button style = ((Button) findViewById(R.id.search_button));
} catch (Exception e) {
Intent i = new Intent();
i.setClass(getApplicationContext(), TEL_Main_Activity.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_tel_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
public void UpdateTextView () {
textView.setText(String.format("%-20s %10s %10s", list[0].name, list[0].number, list[0].support));
for (int x = 1 ; x < list.length & list[x] != null ; x++) {
textView.append("\n" +
(String.format("%-20s %12s %10s", list[x].name, list[x].number, list[x].support)));
}
}
public void Search(View view) {
textView.setText(null);
EditText line = (EditText) findViewById(R.id.search_box);
String[] tokens = line.getText().toString().split(" ");
if (tokens.length == 0)
{
//There was nothing in the search box.
}
else {
list = new Employee[50];
int listCtr = 0; //Keeps ctr for list[]
for (int dbCtr = 0 ; dbCtr < 5000 ; dbCtr++) {
System.out.println(dbCtr);
if (listCtr == 50)
break;
if (employees[dbCtr] == null)
{
//Should have less than 50 listed items and finished searching.
//Now it is okay to update the list view.
UpdateTextView();
break;
}
if (employees[dbCtr].contains(tokens))
{
list[listCtr] = employees[dbCtr];
listCtr++;
}
}
}
}
}
The App purpose: search through company employee listing, display results.(Must have less than 51 results to display)
I don't think that "the other search doesn't stop running" is really a good description of what's going wrong here. I don't see any "threads." I think that the problem is that you're attempting to do the search "on keyPress," therefore "with every keyPress."
A much better way to think of what you're trying to do here would be: "I want to automatically 'push the button' as soon as the user stops typing."
So, basically, when the user starts pressing keys, you'll start a timer (if such a timer isn't already running) set to go off in, say, 1/2-second. Then, in any case, you'll set a flag to true which indicates that "the user has recently pressed a key."
When the timer goes off, it checks to see if this flag is true. If so, it sets the flag to false and reschedules the timer to go-off again in another 1/2-second. Otherwise, it does what "pressing the button" used to do, then it will reset the (separate) flag that indicates that the timer is running.
As long as the user is pressing at least one key every 1/2 second, the timer will continue to reschedule itself (and, no one else will attempt to start the timer since they can see that the timer's running). Eventually, though, the timer will see that the key-has-been-pressed flag has remained false for half-a-second. That's when it "presses the button," causing the search to take place.
For a thorough solution, the timer-routine, after performing the search, would check the "key-has-been-pressed" flag once again. If it's still false, then the user really has stopped typing and it's time to present those search-results. Otherwise, the timer-routine should start rescheduling itself again.
Eventually, the user will stop typing. The timer will run the search, and, having done so, will see that the user still hasn't typed anything more. Results will then be displayed (for the first time).

how text to speech works in android

I am creating an android application using text to speech capability I used the built in text to speech
I only want to know how it has been developed and maintained in the android SDK, if any one knows a termed paper about developing text to speech in android i'll be blessed
This thread will help. Also, an abstract class for TTS Engine Implementation was introduced in API Level 14. Check this link. You can also read this information about speech synthesis to guide you on how it should be implemented.
by luck i was working in this also , take my code
package com.example.texttospeech;
import java.util.Locale;
import android.os.Bundle;
import android.app.Activity;
import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeech.OnInitListener;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
public class MainActivity extends Activity implements OnClickListener, OnInitListener {
private TextToSpeech tts;
EditText editxt;
Button b1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tts = new TextToSpeech(this , this);
editxt = (EditText) findViewById(R.id.editText1);
b1 = (Button) findViewById(R.id.read);
b1.setOnClickListener(this);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.read:
convert_text();
break;
default:
break;
}
}
private void convert_text() {
String speech = editxt.getText().toString();
tts.speak(speech, TextToSpeech.QUEUE_FLUSH, null);
}
#Override
public void onInit(int status) {
if(status == TextToSpeech.SUCCESS){
int result = tts.setLanguage(Locale.getDefault());
if(result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED){
Log.e("DEBUG" , "Language Not Supported");}
else{
b1.setEnabled(true);
convert_text();
}
}
else{
Log.i("DEBUG" , "MISSION FAILED");
}
}
#Override
protected void onDestroy() {
super.onDestroy();
if (tts != null){
tts.stop();
tts.shutdown();
}
}
}
mylayout activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:textSize="21sp"
android:layout_marginTop="23dp"
android:text="Text To Speech Test" />
<EditText
android:id="#+id/editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/textView1"
android:layout_centerHorizontal="true"
android:layout_marginTop="35dp"
android:ems="10" />
<Button
android:id="#+id/read"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/textView1"
android:layout_below="#+id/editText1"
android:layout_marginLeft="46dp"
android:layout_marginTop="50dp"
android:text="Read" />
</RelativeLayout>

Android button returning to activity from layout

I can't find a way how to make it work. So here it goes:
Application starts and I press Option menu and it offers me "Settings" option, and when I click it, it goes to layout called "help.xml" which shows me some text ...And in that layout I created a button which must return me to my activity ( the window which is shown when app starts)
I tried making a back button works but I failed cause I need for user to wait 30 seconds until the next image switch , and by making back button works hw would exploit it..
Sorry for my English, it is not my native language ;)
//** Povratak= return **//
MainActivity
package com.example.ams;
import java.util.Random;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
public class MainActivity extends Activity {
final Random rnd = new Random();
ImageView img = null;
Button btnRandom = null;
#Override
protected void onCreate(
final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
img = (ImageView) findViewById(R.id.imgRandom);
btnRandom = (Button) findViewById(R.id.btnRandom);
}
protected final static int getResourceID
(final String resName, final String resType, final Context ctx)
{
final int ResourceID =
ctx.getResources().getIdentifier(resName, resType,
ctx.getApplicationInfo().packageName);
if (ResourceID == 0)
{
throw new IllegalArgumentException
(
"No resource string found with name " + resName
);
}
else
{
return ResourceID;
}
}
public void clickHandler(final View v)
{
switch(v.getId())
{
case R.id.btnRandom:
{
if (!btnRandom.isEnabled())
{
return;
}
// I have 3 images named img_0 to img_2, so...
final String str = "img_" + rnd.nextInt(45);
img.setImageDrawable
(
getResources().getDrawable(getResourceID(str, "drawable",
getApplicationContext()))
);
btnRandom.setEnabled(false);
new CountDownTimer(30000, 1000) // Wait 30 secs, tick every 1 sec
{
#Override
public final void onTick(final long millisUntilFinished)
{
btnRandom.setText("Pričekaj do sljedeće kartice: " + (millisUntilFinished / 1000));
}
#Override
public final void onFinish()
{
btnRandom.setText("PROMIJENI KARTICU !");
btnRandom.setEnabled(true);
}
}.start();
break;
}
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.action_settings:
setContentView(R.layout.help);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater=getMenuInflater();
inflater.inflate(R.menu.main, menu);
return super.onCreateOptionsMenu(menu);
}
public void goBack(View v){
startActivity(new Intent(this, MainActivity.class));
}
#Override
public void onBackPressed() {
}
}
activity_main.xml
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".MainActivity"
android:background="#drawable/bgi"
>
<ImageView
android:id="#+id/imgRandom"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
/>
<Button
android:id="#+id/btnRandom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/imgRandom"
android:layout_alignParentBottom="true"
android:layout_alignRight="#+id/imgRandom"
android:onClick="clickHandler"
android:text=" Promijeni karticu !"
android:textColor="#ffffff"
android:textSize="25dp" />
help.xml
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ScrollView
android:id="#+id/SCROLLER_ID"
android:layout_width="fill_parent"
android:layout_height="450dp"
android:fillViewport="true"
android:scrollbars="vertical" >
<TextView
android:id="#+id/textView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:enabled="true"
android:freezesText="false"
android:overScrollMode="always"
android:scrollbarAlwaysDrawVerticalTrack="true"
android:scrollbarStyle="insideOverlay"
android:scrollbars="vertical"
android:text="UVOD:Uz svaki scenario organizator moze odrediti da se koristi "AMS sustav" zbog realnijeg pristupa igri i viseg stupnja MILSIM-a. Organizator bira medice (ili kako se vec odredi) i oni moraju imati prilikom pocetka igre 46 kartica. />
</ScrollView>
<Button
android:id="#+id/button1"
android:layout_width="320dp"
android:layout_height="wrap_content"
android:text="Povratak" />
So I want to "Povratak" button works, it needs to send user to lets called it "main menu" (go back)..
EDITED AND FIXED:
have another question, is there any way to activity remebers the counting, because when you enter the app you click button which random generates a image from drawable and it doesn't let user to press that button for 30 secs.. the problem now is that when you are waiting for counter go to 0 you can easily press option menu, click settings and click "povratak" ,which starts activity all over again and the counter losses its point because user can now again press button that generates image (and I dont want that):/
In your help.xml for your Povratak button, use:
android:onClick="goBack"
Then in your Help.java, use:
public void goBack(View v){
setContentView(R.layout.activity_main);
}
there is two way to fix that problem ,the first one is that you need to call the finish methode in your call back methode of the button like this :
in your help.xml file :
in your class Help.java implement your methode as follow :
public void Povratak(View v)
{
finish();
}
if that does not fix your problem you can start an intent to go to your main activity, you have to change the implimentation of your call back methode :
public void Povratak(View v){
Intent intent=new Intent(this,MainActivity.class);
startactivity(intent);
finish();
}
hope this help ,for more information about activity and intent you can see this tutoriel
click here

How can i play videos in webview android?

Since im quite new to Java and Android apps, i had to ask this question because im working for 10 hours and couldnt achive anything. I made a full screen web app in eclipse but i cant see videos in there. Here's my codes:
Tarim.java
package com.tarim.tarimvideo;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.view.MotionEvent;
import android.view.View;
import android.webkit.WebView;
import com.tarim.tarimvideo.util.SystemUiHider;
#SuppressLint("SetJavaScriptEnabled")
public class Tarim extends Activity {
private static final boolean AUTO_HIDE = true;
private static final int AUTO_HIDE_DELAY_MILLIS = 3000;
private static final boolean TOGGLE_ON_CLICK = true;
private static final int HIDER_FLAGS = SystemUiHider.FLAG_HIDE_NAVIGATION;
private SystemUiHider mSystemUiHider;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tarim);
final View controlsView = findViewById(R.id.fullscreen_content_controls);
final View contentView = findViewById(R.id.fullscreen_content);
WebView webView = (WebView)findViewById(R.id.tarayici);
webView.getSettings().setJavaScriptEnabled(true);
webView.loadUrl("http://www.youtube.com/watch?v=W8SCqLkHDqw");
// Set up an instance of SystemUiHider to control the system UI for
// this activity.
mSystemUiHider = SystemUiHider.getInstance(this, contentView,
HIDER_FLAGS);
mSystemUiHider.setup();
mSystemUiHider
.setOnVisibilityChangeListener(new SystemUiHider.OnVisibilityChangeListener() {
// Cached values.
int mControlsHeight;
int mShortAnimTime;
#Override
#TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
public void onVisibilityChange(boolean visible) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
// If the ViewPropertyAnimator API is available
// (Honeycomb MR2 and later), use it to animate the
// in-layout UI controls at the bottom of the
// screen.
if (mControlsHeight == 0) {
mControlsHeight = controlsView.getHeight();
}
if (mShortAnimTime == 0) {
mShortAnimTime = getResources().getInteger(
android.R.integer.config_shortAnimTime);
}
controlsView
.animate()
.translationY(visible ? 0 : mControlsHeight)
.setDuration(mShortAnimTime);
} else {
// If the ViewPropertyAnimator APIs aren't
// available, simply show or hide the in-layout UI
// controls.
controlsView.setVisibility(visible ? View.VISIBLE
: View.GONE);
}
if (visible && AUTO_HIDE) {
// Schedule a hide().
delayedHide(AUTO_HIDE_DELAY_MILLIS);
}
}
});
// Set up the user interaction to manually show or hide the system UI.
contentView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (TOGGLE_ON_CLICK) {
mSystemUiHider.toggle();
} else {
mSystemUiHider.show();
}
}
});
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Trigger the initial hide() shortly after the activity has been
// created, to briefly hint to the user that UI controls
// are available.
delayedHide(100);
}
View.OnTouchListener mDelayHideTouchListener = new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (AUTO_HIDE) {
delayedHide(AUTO_HIDE_DELAY_MILLIS);
}
return false;
}
};
Handler mHideHandler = new Handler();
Runnable mHideRunnable = new Runnable() {
#Override
public void run() {
mSystemUiHider.hide();
}
};
private void delayedHide(int delayMillis) {
mHideHandler.removeCallbacks(mHideRunnable);
mHideHandler.postDelayed(mHideRunnable, delayMillis);
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tarim.tarimvideo"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme">
<activity
android:name="com.tarim.tarimvideo.Tarim"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="#string/app_name"
android:theme="#style/FullscreenTheme" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
activity.tarim.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#0099cc"
tools:context=".Tarim" >
<!--
The primary full-screen view. This can be replaced with whatever view
is needed to present your content, e.g. VideoView, SurfaceView,
TextureView, etc.
-->
<TextView
android:id="#+id/fullscreen_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:keepScreenOn="true"
android:text="#string/dummy_content"
android:textColor="#33b5e5"
android:textSize="50sp"
android:textStyle="bold" />
<!--
This FrameLayout insets its children based on system windows using
android:fitsSystemWindows.
-->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true" >
<LinearLayout
android:id="#+id/fullscreen_content_controls"
style="?buttonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:background="#color/black_overlay"
android:orientation="horizontal"
tools:ignore="UselessParent" >
<Button
android:id="#+id/dummy_button"
style="?buttonBarButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="#string/dummy_button" />
</LinearLayout>
<WebView
android:id="#+id/tarayici"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
</FrameLayout>
Please note that im in this Java thing just for 10 hours, so if you can explain me as much as simple, it would be so great.
It does not look like it is possible in a WebView without the assistance of flash. Please look at this: Youtube in a webview (used for reference). And look at this for a flash demo: Flash demo. Lastly this might also be helpful, it is Android's YouTube API.
Just put a .html file in your SDCARD which contain your video link.(mention video link as content:\\).and load that .html file to the webview.

Categories

Resources