I want to create app of hockey results. On home page, user select his favorite team and than he can see in fragment Future Matches - matches of his favorite team.
After this, he can select his favorite match (by click on match) and than, If score is changed in this match, user get notification about changed score.
But I have problem, because when I see future matches, after click on match, application drop.
I don´t have any idea about solve this problem.
I need help with this.
public class Future_matches extends Fragment {
private static Future_matches fragment;
private int favorite_team_id;
private SharedPreferences sp;
private RecyclerView rv_futureMatches;
// private FutureMatchesAdapter adapter;
private List<FutureMatchModel> teams;
private SharedPreferences.Editor ed;
List<Thread> listOfActiveThreads;
private RecyclerView.Adapter<FutureMatchesHolder> adapter;
private RecyclerView.LayoutManager layoutManager;
public Future_matches() {
}
public static Future_matches newInstance() {
if (fragment == null)
fragment = new Future_matches();
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
listOfActiveThreads = new ArrayList<>();
sp = getActivity().getSharedPreferences(Tools.PACKAGE_NAME, Context.MODE_PRIVATE);
favorite_team_id = sp.getInt(Tools.FAVORITE_TEAM_ID, -1);
ed = sp.edit();
}
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootview = inflater.inflate(R.layout.future_matches, container, false);
rv_futureMatches = rootview.findViewById(R.id.rv_future_matches);
RecyclerView.LayoutManager lm = new LinearLayoutManager(getActivity());
// rv_futureMatches.setLayoutManager(lm);
// rv_futureMatches.setHasFixedSize(true);
if (favorite_team_id == -1) {
Toast.makeText(getActivity(), R.string.warning_future_matches_choose_favorite_team, Toast.LENGTH_SHORT).show();
} else {
Tools.getApi().getFutureMatches(favorite_team_id, "2018-12-27", "2019-05-12").enqueue(new Callback<JsonObject>() {
#Override
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
if (response.code() == 200) {
teams = JsonTools.convertJsonToFutureMatches(response.body());
// JsonObject data = response.body();
layoutManager = new LinearLayoutManager(getActivity());
layoutManager = new LinearLayoutManager(getContext());
// adapter = new FutureMatchesAdapter(JsonTools.convertJsonToFutureMatches(data), new WeakReference<Context>(getActivity()));
adapter = new FutureMatchesAdapter(teams, new WeakReference<Context>(getActivity()), new FutureMatchesAdapter.TeamClickHandler() {
#Override
public void onClick(int id) {
takeCareOfChanges(id);
}
});
rv_futureMatches.setHasFixedSize(true);
rv_futureMatches.setLayoutManager(layoutManager);
rv_futureMatches.setAdapter(adapter);
}
}
#Override
public void onFailure(Call<JsonObject> call, Throwable t) {
Toast.makeText(getActivity(), t.getMessage(), Toast.LENGTH_LONG).show();
}
});
}
return rootview;
}
private boolean isItemInList(int id) {
if (sp.contains(Tools.PREFS_PICKED_GAMES)) {
Set<String> result = sp.getStringSet(Tools.PREFS_PICKED_GAMES, null);
if (result.contains(Integer.toString(id))) {
return true;
} else {
return false;
}
} else
return false;
}
private void takeCareOfChanges(int id) {
if (sp.contains(Tools.PREFS_PICKED_GAMES)) {
Set<String> result = sp.getStringSet(Tools.PREFS_PICKED_GAMES, null);
if (isItemInList(id)) {
result.remove(Integer.toString(id));
ed.putStringSet(Tools.PREFS_PICKED_GAMES, result);
quitService(id);
} else {
result.add(Integer.toString(id));
ed.putStringSet(Tools.PREFS_PICKED_GAMES, result);
launchService(id);
}
} else {
Set<String> result = new HashSet<>();
result.add(Integer.toString(id));
ed.putStringSet(Tools.PREFS_PICKED_GAMES, result);
launchService(id);
}
ed.apply();
}
private void launchService(final int id){
getActivity().startService(new Intent().putExtra(Tools.INTENT_EXTRA_ID,id));
}
private void quitService(int id){
LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(new Intent().setAction(Tools.INTENT_ACTION_STOP_SERVICE).putExtra(Tools.INTENT_EXTRA_ID,id));
}
}
public class GameChangeService extends Service {
private final static String TAG = "GameChangeService";
private BroadcastReceiver broadcastReceiver;
private Handler h;
private SharedPreferences sp;
Notification notif;
NotificationManager notifManager;
private SharedPreferences.Editor ed;
private Runnable r;
private int id;
private String CHANNEL_ID = "ID";
private int notifId = 1000;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
sp = getSharedPreferences(Tools.PACKAGE_NAME, Context.MODE_PRIVATE);
ed = sp.edit();
notifManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
h = new Handler();
broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
stopSelf();
}
};
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, new IntentFilter(Tools.INTENT_ACTION_STOP_SERVICE));
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
id = intent.getIntExtra(Tools.INTENT_EXTRA_ID, -1);
if (id == -1) {
stopSelf();
} else {
r = new Runnable() {
#Override
public void run() {
doStuff(id);
h.postDelayed(r, 15000);
}
};
h.post(r);
return Service.START_STICKY;
}
//TOTO TU JE VELMI DISKUTABILNE
return Service.START_STICKY;
}
private void doStuff(final int id) {
//TODO: Checkni pls ci je boxscore updatovany live alebo nie. Ak je tak ho mozes pouzit v IApiDefinition namiesto live feed
// JA> V schedule je s gamepk aj online zapas s golmi - staci to pouzit
ApiTools.getApi().getGame(id).enqueue(new Callback<JsonObject>() {
#Override
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
if (sp.contains(Integer.toString(id))) {
int povodnyPocetGolovVZapase = sp.getInt(Integer.toString(id), 0);
//Z responsu zistit kolko eventov je teraz v zapase, t.j. ci uz zapas zacal.
//Dalej zistit ci su tam nejake eventy, ktore maju typ goal alebo ENDGAME (asi).
//AK sa zmenil pocet golov, tak posli notifikaciu ze padol gol aj s novym stavom
JsonObject data = response.body();
//pouzijem lastmatchmodel, aj ked to nie je pre toto robene, ale data mi stacia aj z neho
//List<LastMatchModel> livezapasy = new ArrayList<>();
//vytiahnem si zoznam
JsonArray zoznamZapasovZJsonu = data.get("dates").getAsJsonArray();
for (int i = 0; i < zoznamZapasovZJsonu.size(); i++) {
//pouzijem lastmatchmodel, aj ked to nie je pre toto robene, ale data mi stacia aj z neho
LastMatchModel novyZapas = new LastMatchModel();
JsonObject zapasDate = zoznamZapasovZJsonu.get(i).getAsJsonObject();
JsonArray games = zapasDate.get("games").getAsJsonArray();
if (games.size() >= 1) {
JsonObject teams = games.get(0).getAsJsonObject().get("teams").getAsJsonObject();
int golyHostia = teams.get("away").getAsJsonObject().get("score").getAsInt();
String timHostia = teams.get("away").getAsJsonObject().get("team").getAsJsonObject().get("name").getAsString();
int golyDomaci = teams.get("home").getAsJsonObject().get("score").getAsInt();
String timDomaci = teams.get("home").getAsJsonObject().get("team").getAsJsonObject().get("name").getAsString();
if (golyDomaci + golyHostia != povodnyPocetGolovVZapase) {
Intent intent = new Intent(GameChangeService.this, MatchNotification.class);
PendingIntent pendingIntent = PendingIntent.getActivity(GameChangeService.this, 0, intent, 0);
createNotificationChannel();
final NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(GameChangeService.this, CHANNEL_ID)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("GOAL")
.setContentText(timDomaci + golyDomaci + " vs " + golyHostia + timHostia)
.setContentIntent(pendingIntent)
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
NotificationManagerCompat nm = NotificationManagerCompat.from(GameChangeService.this);
nm.notify(notifId, mBuilder.build());
}
}
}
} else {
int povodnyPocetEventovVZapase = 0;
//Z responsu zistit kolko eventov je teraz v zapase, t.j. ci uz zapas zacal.
//Dalej zistit ci su tam nejake eventy, ktore maju typ goal alebo ENDGAME (asi).
//AK sa zmenil pocet golov, tak posli notifikaciu ze padol gol aj s novym stavom
}
}
#Override
public void onFailure(Call<JsonObject> call, Throwable t) {
Log.e(GameChangeService.TAG, "Nebavi to ");
}
});
}
#Override
public void onDestroy() {
super.onDestroy();
if (h != null)
h.removeCallbacks(r);
LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver);
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = "Name of the channel";
String description = "Description of the channel";
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
channel.setDescription(description);
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
}
Run in Android Studio inform about errors:
https://ctrlv.cz/shots/2019/01/03/Y6RS.png
or
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.luky.nhlvysledky, PID: 23251
java.lang.IllegalArgumentException: Service Intent must be explicit: Intent { (has extras) }
at android.app.ContextImpl.validateServiceIntent(ContextImpl.java:1519)
at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1560)
at android.app.ContextImpl.startService(ContextImpl.java:1532)
at android.content.ContextWrapper.startService(ContextWrapper.java:664)
at com.example.luky.nhlvysledky.Future_matches.launchService(Future_matches.java:148)
at com.example.luky.nhlvysledky.Future_matches.takeCareOfChanges(Future_matches.java:142)
at com.example.luky.nhlvysledky.Future_matches.access$300(Future_matches.java:33)
at com.example.luky.nhlvysledky.Future_matches$1$1.onClick(Future_matches.java:93)
at com.example.luky.nhlvysledky.RecycleView.FutureMatchesHolder$1.onClick(FutureMatchesHolder.java:46)
at android.view.View.performClick(View.java:6597)
at android.view.View.performClickInternal(View.java:6574)
at android.view.View.access$3100(View.java:778)
at android.view.View$PerformClick.run(View.java:25885)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
You need to explicitly define which service you are starting in your intent.
getActivity().startService(new Intent(getActivity(), GameChangeService.class).putExtra(Tools.INTENT_EXTRA_ID,id));
You will also need to define your service in your AndroidManifest.xml.
<service android:enabled="true" android:name=".GameChangeService" />
Related
My app is a tracking app where I want to track user location in a service and then display every location in a fragment.
I have a problem with background service: my service is stopped after some minutes (sometimes < 10 minutes, sometimes > 30 minutes).
I start my location service in this fragment and everything goes fine when I use my app.
The problem is when I close (not kill) my app and start something else on my phone (or just block it), after a few minutes my service is stopped and I don't know why.
I show a foreground notification when my service is running but android system still stops it, I notice this because my notification disappear and my app restarts.
Here is my code for the service:
public class LocationService extends Service {
private static final String TAG = "LocationService";
public static final String NEW_VALUE_INTENT_ACTION = "service_new_value";
public static final String INTENT_LATITUDE = "latitude";
public static final String INTENT_LONGITUDE = "longitude";
public static final String INTENT_SPEED = "speed";
public static final String INTENT_ACCURACY = "accuracy";
private static final long TWO_MINUTES = 1000 * 60 * 2;
private static final long INTERVAL = 5000;
private static final long FASTEST_INTERVAL = 2000;
private int ONGOING_NOTIFICATION = 1111;
private Location currentLocation;
NotificationCompat.Builder builder = null;
private LocationRequest mLocationRequest;
/**
* Provides access to the Fused Location Provider API.
*/
private FusedLocationProviderClient mFusedLocationClient;
/**
* Callback for changes in location.
*/
private LocationCallback mLocationCallback;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
Log.d(LocationService.TAG, "LocationService ---> onCreate()");
super.onCreate();
}
#Override
public void onDestroy() {
Log.d(LocationService.TAG, "LocationService ---> onDestroy()");
super.onDestroy();
stopForeground(true);
mFusedLocationClient.removeLocationUpdates(mLocationCallback);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(LocationService.TAG, "LocationService ---> onStartCommand()");
startServiceTask();
return super.onStartCommand(intent, flags, startId);
}
#Override
public boolean onUnbind(Intent intent) {
Log.d(LocationService.TAG, "LocationService ---> onUnbind()");
return super.onUnbind(intent);
}
private void startServiceTask() {
Log.d(LocationService.TAG, "GpsService ---> Starting ...");
setServiceAsForeground();
initFusedLocationProvider();
Log.d(LocationService.TAG, "MyStartedService ---> Starting ...");
}
private void initFusedLocationProvider() {
mFusedLocationClient = new FusedLocationProviderClient(this);
mLocationRequest = new LocationRequest();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(INTERVAL);
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
if (currentLocation == null)
currentLocation = locationResult.getLastLocation();
else if (isBetterLocation(locationResult.getLastLocation(), currentLocation)) {
Log.d(TAG, "onLocationChanged(): Updating Location ... " + currentLocation.getProvider());
currentLocation = locationResult.getLastLocation();
}
notifyValueUpdate();
} }, getMainLooper());
}
protected boolean isBetterLocation(Location location, Location currentBestLocation) {
if (currentBestLocation == null) {
// A new location is always better than no location
return true;
}
// Check whether the new location fix is newer or older
long timeDelta = location.getTime() - currentBestLocation.getTime();
boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
boolean isNewer = timeDelta > 0;
// If it's been more than two minutes since the current location, use
// the new location
// because the user has likely moved
if (isSignificantlyNewer) {
return true;
// If the new location is more than two minutes older, it must be
// worse
} else if (isSignificantlyOlder) {
return false;
}
// Check whether the new location fix is more or less accurate
int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation
.getAccuracy());
boolean isLessAccurate = accuracyDelta > 0;
boolean isMoreAccurate = accuracyDelta < 0;
boolean isSignificantlyLessAccurate = accuracyDelta > 200;
// Check if the old and new location are from the same provider
boolean isFromSameProvider = isSameProvider(location.getProvider(),
currentBestLocation.getProvider());
// Determine location quality using a combination of timeliness and
// accuracy
if (isMoreAccurate) {
return true;
} else if (isNewer && !isLessAccurate) {
return true;
} else if (isNewer && !isSignificantlyLessAccurate
&& isFromSameProvider) {
return true;
}
return false;
}
/** Checks whether two providers are the same */
private boolean isSameProvider(String provider1, String provider2) {
if (provider1 == null) {
return provider2 == null;
}
return provider1.equals(provider2);
}
private void setServiceAsForeground() {
Log.d(LocationService.TAG, "GpsService ---> setServiceAsForeground()");
// Prepare the intent triggered if the notification is selected
Intent intent = new Intent(this, LocationService.class);
PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent, 0);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
builder = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
int importance = NotificationManager.IMPORTANCE_LOW;
NotificationChannel notificationChannel = new NotificationChannel("ID", "Name", importance);
notificationManager.createNotificationChannel(notificationChannel);
builder = new NotificationCompat.Builder(getApplicationContext(), notificationChannel.getId());
} else {
builder = new NotificationCompat.Builder(getApplicationContext());
}
Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
v.vibrate(VibrationEffect.createOneShot(500, VibrationEffect.DEFAULT_AMPLITUDE));
} else {
//deprecated in API 26
v.vibrate(500);
}
// Build the notification
// Use NotificationCompat.Builder instead of just Notification.Builder to support older Android versions
Notification notification = builder.setContentTitle("MyMovements")
.setContentText("Running ...")
.setSmallIcon(getNotificationIcon())
.setBadgeIconType(getNotificationIcon())
.setContentIntent(pIntent)
.setAutoCancel(true).build();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
startForeground(ONGOING_NOTIFICATION, notification, FOREGROUND_SERVICE_TYPE_LOCATION);
}
else {
startForeground(ONGOING_NOTIFICATION,notification);
}
}
private int getNotificationIcon(){
SharedPreferences settings = this.getSharedPreferences(MainActivity.PREFERENCE,0);
String icon = settings.getString(MapFragment.NOTIFICATION_PREF, " ");
switch (icon) {
case "Walking":
return R.drawable.walk;
case "Public Transportation":
return R.drawable.bus;
case "Driving":
return R.drawable.car;
default:
return 0;
}
}
private void updateNotification(){
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
String conc = "Running...\n" + "Lat: " + currentLocation.getLatitude() + " " + "Lng: " + currentLocation.getLongitude();
Notification notification = builder.setStyle(new NotificationCompat.BigTextStyle()
.bigText(conc))
.setContentText(conc).build();
notificationManager.notify(ONGOING_NOTIFICATION, notification);
}
private void notifyValueUpdate(){
Log.d(TAG, "MyStartedService ---> notifyValueUpdate()");
if(currentLocation != null) {
updateNotification();
Log.d(LocationService.TAG, currentLocation.getProvider());
Intent broadcastIntent = new Intent();
broadcastIntent.setAction(NEW_VALUE_INTENT_ACTION);
Bundle bundle = new Bundle();
bundle.putDouble(INTENT_LATITUDE, currentLocation.getLatitude());
bundle.putDouble(INTENT_LONGITUDE, currentLocation.getLongitude());
bundle.putDouble(INTENT_SPEED, currentLocation.getSpeed()*3.6);
bundle.putDouble(INTENT_ACCURACY, currentLocation.getAccuracy());
broadcastIntent.putExtras(bundle);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcastIntent);
}
}
}
I started my service in OnServiceCommand() -> startServiceTask() -> setServiceAsForeground()
I will really appreciate any tips for my code (this is a scholar project and this is my first app, so probably I am doing something wrong).
Thanks to everyone
My Main Activity has three tabs. Each tab is a fragment. Now if you change the theme (white and dark are available), the activity is being recreated so that the change takes effect. But the app crashes.
How I deal with the fragments:
if (savedInstanceState == null) {
pageadapter = new SectionsPageAdapter(getSupportFragmentManager());
rFragMore = new RoomlistFragmentMore();
rFragMyRooms = new RoomlistFragmentMyRooms();
rFragFavs = new RoomlistFragmentFavorites();
} else {
rFragMyRooms = (RoomlistFragmentMyRooms)pageadapter.getItem(0);
rFragFavs = (RoomlistFragmentFavorites)pageadapter.getItem(1);
rFragMore = (RoomlistFragmentMore)pageadapter.getItem(2);
pageadapter.clearAdapter();
pageadapter = new SectionsPageAdapter(getSupportFragmentManager());
}
How I set up the Adapter:
private void setupViewPager(ViewPager viewPager) {
pageadapter.addFragment(rFragMyRooms, getResources().getString(R.string.myrooms));
pageadapter.addFragment(rFragFavs, getResources().getString(R.string.favorites));
pageadapter.addFragment(rFragMore, getResources().getString(R.string.more));
viewPager.setAdapter(pageadapter);
}
My Adapter:
public class SectionsPageAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
public void clearAdapter() {
mFragmentList.clear();
mFragmentTitleList.clear();
}
public SectionsPageAdapter(FragmentManager fm) {
super(fm);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
}
And the Error Log:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.io.FileInputStream android.content.Context.openFileInput(java.lang.String)' on a null object reference
at com.yannick.mychatapp.RoomlistFragmentMore.readFromFile(RoomlistFragmentMore.java:246)
at com.yannick.mychatapp.RoomlistFragmentMore.addRoomToList(RoomlistFragmentMore.java:121)
at com.yannick.mychatapp.RoomlistFragmentMore.access$000(RoomlistFragmentMore.java:46)
at com.yannick.mychatapp.RoomlistFragmentMore$1.onDataChange(RoomlistFragmentMore.java:79)
at com.google.firebase.database.core.ValueEventRegistration.fireEvent(com.google.firebase:firebase-database##16.0.4:75)
at com.google.firebase.database.core.view.DataEvent.fire(com.google.firebase:firebase-database##16.0.4:63)
at com.google.firebase.database.core.view.EventRaiser$1.run(com.google.firebase:firebase-database##16.0.4:55)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
EDIT: the code of RoomlistFragmentMore
public class RoomlistFragmentMore extends Fragment {
private ListView listView;
private List<HashMap<String, String>> listItems = new ArrayList<>();
private String raumname, theme;
private static String userID = "";
private SimpleAdapter adapter;
private DatabaseReference root = FirebaseDatabase.getInstance().getReference().getRoot().child("rooms");
private ArrayList<Room> raumliste = new ArrayList<>();
private TextView keinraumgefunden;
private String[] kat;
private static final String TAG = "RoomlistFragmentMore";
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.roomlist_fragment_more,container,false);
listView = view.findViewById(R.id.listView);
keinraumgefunden = view.findViewById(R.id.keinraumgefunden);
kat = getResources().getStringArray(R.array.categories);
theme = readFromFile("mychatapp_theme.txt");
adapter = new SimpleAdapter(getActivity(), listItems, R.layout.listlayout,
new String[]{"name", "kat", "lock", "newest"},
new int[]{R.id.raumname, R.id.raumkat, R.id.raumlock, R.id.raumdatum});
listView.setAdapter(adapter);
root.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
addRoomToList(dataSnapshot);
}
#Override
public void onCancelled(DatabaseError databaseError) {
Toast.makeText(getActivity(), R.string.nodatabaseconnection, Toast.LENGTH_SHORT).show();
}
});
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
int position = listView.getPositionForView(view);
String roomname = listItems.get(position).values().toArray()[0].toString();
Room room = findRoom(raumliste, roomname);
request_password(room, position);
}
});
adapter.registerDataSetObserver(new DataSetObserver() {
#Override
public void onChanged() {
if (raumliste.isEmpty()) {
keinraumgefunden.setText(R.string.noroomfound);
} else {
keinraumgefunden.setText("");
}
}
});
return view;
}
private void addRoomToList(DataSnapshot dataSnapshot) {
HashMap<String, String> raeume = new HashMap<>();
raumliste.clear();
for(DataSnapshot uniqueKeySnapshot : dataSnapshot.getChildren()){
String name = uniqueKeySnapshot.getKey();
for(DataSnapshot roomSnapshot : uniqueKeySnapshot.getChildren()){
Room room = roomSnapshot.getValue(Room.class);
room.setRaumname(name);
if (!room.getPasswd().equals(readFromFile("mychatapp_raum_" + name + ".txt"))) {
raeume.put(name, kat[Integer.parseInt(room.getCaty())]+"/"+"\uD83D\uDD12"+"/");
raumliste.add(room);
}
break;
}
}
listItems.clear();
Iterator it = raeume.entrySet().iterator();
while (it.hasNext()){
HashMap<String, String> resultsMap = new HashMap<>();
Map.Entry pair = (Map.Entry)it.next();
resultsMap.put("name", pair.getKey().toString());
String daten = pair.getValue().toString();
String caty = daten.substring(0, daten.indexOf("/"));
String lock = daten.substring(daten.indexOf("/")+1, daten.lastIndexOf("/"));
String time = daten.substring(daten.lastIndexOf("/")+1, daten.length());
String newestTime = "";
int index = 0;
resultsMap.put("kat", caty);
resultsMap.put("lock", lock);
resultsMap.put("newest", newestTime);
if (time.equals("")) {
listItems.add(resultsMap);
} else {
listItems.add(index, resultsMap);
}
}
adapter.notifyDataSetChanged();
}
private void request_password(final Room room, final int position) {
LayoutInflater inflater = LayoutInflater.from(getContext());
View view = inflater.inflate(R.layout.enter_room, null);
raumname = room.getRaumname();
userID = readFromFile("mychatapp_userid.txt");
final EditText input_field = view.findViewById(R.id.room_password);
AlertDialog.Builder builder;
if (theme.equals(getResources().getStringArray(R.array.themes)[1])) {
builder = new AlertDialog.Builder(new ContextThemeWrapper(getActivity(), R.style.AlertDialogDark));
} else {
builder = new AlertDialog.Builder(getActivity());
}
builder.setTitle(R.string.pleaseenterpassword);
builder.setView(view);
builder.setCancelable(false);
builder.setPositiveButton(R.string.confirm, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
}
});
builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
View view = ((AlertDialog) dialogInterface).getCurrentFocus();
if (view != null) {
InputMethodManager imm = (InputMethodManager)getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
dialogInterface.cancel();
}
});
final AlertDialog alert = builder.create();
alert.setOnShowListener(new DialogInterface.OnShowListener() {
#Override
public void onShow(DialogInterface dialog) {
Button b = alert.getButton(AlertDialog.BUTTON_POSITIVE);
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (input_field.getText().toString().trim().equals(room.getPasswd())) {
Intent tabIntent = new Intent("tab");
LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(tabIntent);
Intent intent = new Intent(getActivity(), ChatActivity.class);
intent.putExtra("room_name", room.getRaumname());
intent.putExtra("user_id",userID);
updateRoomList(position);
writeToFile(room.getPasswd(),"mychatapp_raum_" + raumname + ".txt");
alert.cancel();
startActivity(intent);
} else {
Toast.makeText(getActivity(), R.string.wrongpassword, Toast.LENGTH_SHORT).show();
}
}
});
}
});
alert.show();
}
public Room findRoom(ArrayList<Room> raumliste, String raumname) {
for (Room room : raumliste) {
if (room.getRaumname().equals(raumname)) {
return room;
}
}
return null;
}
public void writeToFile(String text, String datei) {
Context context = getActivity();
try {
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(context.openFileOutput(datei, Context.MODE_PRIVATE));
outputStreamWriter.write(text);
outputStreamWriter.close();
}
catch (IOException e) {
Log.e("Exception", "File write failed: " + e.toString());
}
}
public String readFromFile(String datei) {
Context context = getActivity();
String erg = "";
try {
InputStream inputStream = context.openFileInput(datei);
if ( inputStream != null ) {
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String receiveString = "";
StringBuilder stringBuilder = new StringBuilder();
while ( (receiveString = bufferedReader.readLine()) != null ) {
stringBuilder.append(receiveString);
}
inputStream.close();
erg = stringBuilder.toString();
}
}
catch (FileNotFoundException e) {
Log.e("login activity", "File not found: " + e.toString());
} catch (IOException e) {
Log.e("login activity", "Can not read file: " + e.toString());
}
return erg;
}
private void updateRoomList(int position) {
listItems.remove(position);
adapter.notifyDataSetChanged();
}
}
The NullPointerException occured while onDataChange() was executed (you can see this by reading the stack trace). More specifically, readFromFile() needs a valid Context to open a file.
Since your app crashed we know that getActivity() did return null. How can this happen?
You add the ValueEventListener in onCreateView(). At this point in time, the Fragment has a valid Context (see the documentation for an explanation of the Lifecycle), so all is well for the moment.
But since you do not remove the ValueEventListener, it will continue to fire even if the Fragment is temporarily not attached to the Activity because the user swiped to the next page. The Fragment won't be garbage collected because you keep it in a list and reuse it.
This approach is basically ok if you implement null checks to avoid accessing the Activity, the Context or Views in general while they are not present. Of course, you could consider a stronger separation of the data and the View layer as suggested in this guide to app architecture
I do not know much about android. I am trying to send data over BLE.my code is as follows->. I got it from internet https://developer.android.com/guide/topics/connectivity/bluetooth-le#read
how to properly call this method-> mBluetoothService.mBluetoothGatt = device.connectGatt(cntxt, false, mBluetoothService.mGattCallback);There is crash on this line.
public class BluetoothLeService extends Service {
private final static String TAG = BluetoothLeService.class.getSimpleName();
public BluetoothManager mBluetoothManager;
public BluetoothAdapter mBluetoothAdapter;
public String mBluetoothDeviceAddress;
public BluetoothGatt mBluetoothGatt;
private int mConnectionState = STATE_DISCONNECTED;
private final IBinder mBinder = new LocalBinder();
private static final int STATE_DISCONNECTED = 0;
private static final int STATE_CONNECTING = 1;
private static final int STATE_CONNECTED = 2;
public final static String ACTION_GATT_CONNECTED =
"com.example.bluetooth.le.ACTION_GATT_CONNECTED";
public final static String ACTION_GATT_DISCONNECTED =
"com.example.bluetooth.le.ACTION_GATT_DISCONNECTED";
public final static String ACTION_GATT_SERVICES_DISCOVERED =
"com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED";
public final static String ACTION_DATA_AVAILABLE =
"com.example.bluetooth.le.ACTION_DATA_AVAILABLE";
public final static String EXTRA_DATA =
"com.example.bluetooth.le.EXTRA_DATA";
public final static UUID UUID_HEART_RATE_MEASUREMENT =
UUID.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT);
// Various callback methods defined by the BLE API.
public final BluetoothGattCallback mGattCallback =
new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
mConnectionState = STATE_CONNECTED;
broadcastUpdate(intentAction);
Log.i(TAG, "Connected to GATT server.");
Log.i(TAG, "Attempting to start service discovery:" +
mBluetoothGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "Disconnected from GATT server.");
broadcastUpdate(intentAction);
}
}
#Override
// New services discovered
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
//broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
for (BluetoothGattService gattService : gatt.getServices()) {
Log.i(TAG, "onServicesDiscovered: ---------------------");
Log.i(TAG, "onServicesDiscovered: service=" + gattService.getUuid());
for (BluetoothGattCharacteristic characteristic : gattService.getCharacteristics()) {
Log.i(TAG, "onServicesDiscovered: characteristic=" + characteristic.getUuid());
if (characteristic.getUuid().toString().equals("0000ffe9-0000-1000-8000-00805f9b34fb")) {
Log.w(TAG, "onServicesDiscovered: found LED");
String originalString = "560D0F0600F0AA";
byte[] b = hexStringToByteArray(originalString);
characteristic.setValue(b); // call this BEFORE(!) you 'write' any stuff to the server
mBluetoothGatt.writeCharacteristic(characteristic);
Log.i(TAG, "onServicesDiscovered: , write bytes?! " + byteToHexStr(b));
}
}
}
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
// Result of a characteristic read operation
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
byte[] data = characteristic.getValue();
System.out.println("reading");
System.out.println(new String(data));
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
//...
};
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
sendBroadcast(intent);
}
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i + 1), 16));
}
return data;
}
public static String byteToHexStr(byte[] bytes) {
StringBuilder builder = new StringBuilder();
for (byte b: bytes) {
builder.append(String.format("%02x", b));
}
return builder.toString();
}
private void broadcastUpdate(final String action,
final BluetoothGattCharacteristic characteristic) {
final Intent intent = new Intent(action);
// This is special handling for the Heart Rate Measurement profile. Data
// parsing is carried out as per profile specifications.
if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
int flag = characteristic.getProperties();
int format = -1;
if ((flag & 0x01) != 0) {
format = BluetoothGattCharacteristic.FORMAT_UINT16;
Log.d(TAG, "Heart rate format UINT16.");
} else {
format = BluetoothGattCharacteristic.FORMAT_UINT8;
Log.d(TAG, "Heart rate format UINT8.");
}
final int heartRate = characteristic.getIntValue(format, 1);
Log.d(TAG, String.format("Received heart rate: %d", heartRate));
intent.putExtra(EXTRA_DATA, String.valueOf(heartRate));
} else {
// For all other profiles, writes the data formatted in HEX.
final byte[] data = characteristic.getValue();
if (data != null && data.length > 0) {
final StringBuilder stringBuilder = new StringBuilder(data.length);
for(byte byteChar : data)
stringBuilder.append(String.format("%02X ", byteChar));
intent.putExtra(EXTRA_DATA, new String(data) + "\n" +
stringBuilder.toString());
}
}
sendBroadcast(intent);
}
public class LocalBinder extends Binder {
BluetoothLeService getService() {
return BluetoothLeService.this;
}
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return mBinder;/*return null;*/
}
//...
}
I am calling this class methods from outside like this->
public class DeviceScanActivity extends AppCompatActivity/*ListActivity*/ {
//private LeDeviceListAdapter mLeDeviceListAdapter;
public BluetoothAdapter mBluetoothAdapter;
public /*final*/ BluetoothManager mBluetoothManager;
/*=(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);;*/
private BluetoothLeService mBluetoothService;//= new BluetoothLeService();
public Context cntxt;
ArrayList<ViewHolder> arrayOfUsers2 = new ArrayList<ViewHolder>();
private boolean mScanning;
private boolean mBounded;
private Handler mHandler;
ArrayList<String> mylist = new ArrayList<String>();
private static final int REQUEST_ENABLE_BT = 1;
// Stops scanning after 10 seconds.
private static final long SCAN_PERIOD = 50000;
private static final int PERMISSION_REQUEST_COARSE_LOCATION = 456;
UsersAdapter adapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//getActionBar().setTitle("abc");
mHandler = new Handler();
//this.requestPermissions(rqPerm,req);
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);
// Use this check to determine whether BLE is supported on the device. Then you can
// selectively disable BLE-related features.
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
finish();
}
// Initializes a Bluetooth adapter. For API level 18 and above, get a reference to
// BluetoothAdapter through BluetoothManager.
/*final BluetoothManager*/ mBluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = mBluetoothManager.getAdapter();
// Checks if Bluetooth is supported on the device.
if (mBluetoothAdapter == null ) {
Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();
finish();
return;
}
if( !mBluetoothAdapter.isEnabled())
{
Intent enableBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(getIntent(), 1);
}
// Construct the data source
ArrayList<ViewHolder> arrayOfUsers = new ArrayList<ViewHolder>();
// Create the adapter to convert the array to views
adapter = new UsersAdapter(this, arrayOfUsers);
cntxt=this.getApplicationContext();
Intent i = new Intent(this, BluetoothLeService.class);
bindService(this.getIntent(), mConnection, BIND_AUTO_CREATE);; //if checked, start service
ListView listView = (ListView) findViewById(R.id.mobile_list);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
ViewHolder entry= (ViewHolder) parent.getAdapter().getItem(position);
String address = entry.deviceAddress;
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
Toast.makeText(cntxt, address, Toast.LENGTH_SHORT).show();
//mBluetoothService.mBluetoothDeviceAddress=address;
//mBluetoothService.mBluetoothManager=mBluetoothManager;
mBluetoothService.mBluetoothAdapter = mBluetoothAdapter;
mBluetoothService.mBluetoothGatt = device.connectGatt(cntxt, false, mBluetoothService.mGattCallback);
//Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();
}});
ViewHolder newUser2 = new ViewHolder("adtv2","vvg2");
adapter.add(newUser2);
}
ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceDisconnected(ComponentName name) {
//Toast.makeText(Client.this, "Service is disconnected", 1000).show();
mBounded = false;
mBluetoothService = null;
}
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
//Toast.makeText(Client.this, "Service is connected", 1000).show();
mBounded = true;
BluetoothLeService.LocalBinder mLocalBinder = (BluetoothLeService.LocalBinder)service;
mBluetoothService = mLocalBinder.getService();
}
};
private void scanLeDevice(final boolean enable) {
if (enable) {
// Stops scanning after a pre-defined scan period.
ViewHolder newUser2 = new ViewHolder("adtv2","vvg2");
adapter.add(newUser2);
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
Iterator<ViewHolder> it=arrayOfUsers2.iterator();
while(it.hasNext()) {
ViewHolder currentX = it.next();
adapter.add(currentX);
}
// Do something with the value
}
}, SCAN_PERIOD);
mScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
//invalidateOptionsMenu();
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String permissions[], #NonNull int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_COARSE_LOCATION: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted, yay! Start the Bluetooth device scan.
scanLeDevice(true);
} else {
// Alert the user that this application requires the location permission to perform the scan.
}
}
}
}
// Device scan callback.
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
runOnUiThread(new Runnable() {
#Override
public void run() {
//mLeDeviceListAdapter.addDevice(device);
//mLeDeviceListAdapter.notifyDataSetChanged();
//ViewHolder newUser = new ViewHolder("Nathan", "San Diego");
String deviceName=null, deviceAddress=null;
if(device!=null)
deviceName= device.getName();
if (!(deviceName != null && deviceName.length() > 0))
deviceName = "unknown device";
if(device!=null)
deviceAddress= device.getAddress();
ViewHolder newUser = new ViewHolder(deviceName, deviceAddress);
ViewHolder newUser2 = new ViewHolder("adtv","vvg");
if(!arrayOfUsers2.contains(newUser))
arrayOfUsers2.add(newUser);
//adapter.add(newUser);
}
});
}
};
public class UsersAdapter extends ArrayAdapter<ViewHolder> {
public UsersAdapter(Context context, ArrayList<ViewHolder> users) {
super(context, 0, users);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// Get the data item for this position
ViewHolder user = getItem(position);
// Check if an existing view is being reused, otherwise inflate the view
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.bt_details, parent, false);
}
// Lookup view for data population
TextView tvName = (TextView) convertView.findViewById(R.id.DeviceName);
TextView tvHome = (TextView) convertView.findViewById(R.id.DeviceAddress);
// Populate the data into the template view using the data object
tvName.setText(user.deviceName);
tvHome.setText(user.deviceAddress);
// Return the completed view to render on screen
return convertView;
}
}
public class ViewHolder {
String deviceName;
String deviceAddress;
public ViewHolder(String device, String __address) {
this.deviceName =device;
this.deviceAddress= __address;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ViewHolder a = (ViewHolder) o;
return Objects.equals(deviceAddress, a.deviceAddress);
}
}
}
where I get scan device results in a list. On clicking anyelement of that list I invoke AdapterView.OnItemClickListener(). Then how to send message to the device. How to read those log messages. How to know if the code has send message. How to receive message in other device.I have already done BLE scan, which working fine.But not added the code here.
the log cat report is as follows
FATAL EXCEPTION: main
Process: com.example.root.securityalert, PID: 27945
java.lang.NullPointerException: Attempt to read from field 'android.bluetooth.BluetoothGattCallback com.example.root.securityalert.BluetoothLeService.mGattCallback' on a null object reference
at com.example.root.securityalert.DeviceScanActivity$1.onItemClick(DeviceScanActivity.java:115)
at android.widget.AdapterView.performItemClick(AdapterView.java:310)
at android.widget.AbsListView.performItemClick(AbsListView.java:1156)
at android.widget.AbsListView$PerformClick.run(AbsListView.java:3147)
at android.widget.AbsListView$3.run(AbsListView.java:4062)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6165)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:888)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:778)
I also tried with the code
public class BluetoothSendRecv extends BluetoothGattCallback{
public BluetoothManager mBluetoothManager;
public BluetoothAdapter mBluetoothAdapter;
public String mBluetoothDeviceAddress;
public BluetoothGatt mBluetoothGatt;
private int mConnectionState = STATE_DISCONNECTED;
// private final IBinder mBinder = new BluetoothLeService.LocalBinder();
public Context cntxt;
.......
UUID.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT);
// Various callback methods defined by the BLE API.
public final BluetoothGattCallback mGattCallback =
new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
mConnectionState = STATE_CONNECTED;
broadcastUpdate(intentAction);
Log.i(TAG, "Connected to GATT server.");
Log.i(TAG, "Attempting to start service discovery:" +
mBluetoothGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "Disconnected from GATT server.");
broadcastUpdate(intentAction);
}
}
#Override
// New services discovered
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
//broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
for (BluetoothGattService gattService : gatt.getServices()) {
Log.i(TAG, "onServicesDiscovered: ---------------------");
Log.i(TAG, "onServicesDiscovered: service=" + gattService.getUuid());
for (BluetoothGattCharacteristic characteristic : gattService.getCharacteristics()) {
Log.i(TAG, "onServicesDiscovered: characteristic=" + characteristic.getUuid());
if (characteristic.getUuid().toString().equals("0000fee9-0000-1000-8000-00805f9b34fb"/*0000ffe9-0000-1000-8000-00805f9b34fb"*/)) {
Log.w(TAG, "onServicesDiscovered: found LED");
String originalString = "560D0F0600F0AA";
byte[] b = hexStringToByteArray(originalString);
characteristic.setValue(b); // call this BEFORE(!) you 'write' any stuff to the server
mBluetoothGatt.writeCharacteristic(characteristic);
//Toast.makeText(this., "R.string.error_bluetooth_not_supported", Toast.LENGTH_SHORT).show();
//finish()
System.out.println("Writing Mithun");
Toast.makeText(cntxt, originalString, Toast.LENGTH_SHORT).show();
Log.i(TAG, "onServicesDiscovered: , write bytes?! " + byteToHexStr(b));
}
}
}
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
// Result of a characteristic read operation
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
byte[] data = characteristic.getValue();
System.out.println("reading");
System.out.println(new String(data));
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
//...
};
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
//sendBroadcast(intent);
}
.....
}
Then logcat report is as follows aaaa
D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=6 device=CC:1E:39:39:62:1C
I/ContentValues: Connected to GATT server.
D/BluetoothGatt: discoverServices() - device: CC:1E:39:39:62:1C
I/ContentValues: Attempting to start service discovery:true
D/BluetoothGatt: onSearchComplete() = Device=CC:1E:39:39:62:1C Status=0
I/ContentValues: onServicesDiscovered: ---------------------
I/ContentValues: onServicesDiscovered: service=00001800-0000-1000-8000-00805f9b34fb
I/ContentValues: onServicesDiscovered: characteristic=00002a00-0000-1000-8000-00805f9b34fb
I think this condition is not fullfilled
if(characteristic.getUuid().toString().equals("0000fee9-0000-1000-8000-00805f9b34fb"/*0000ffe9-0000-1000-8000-00805f9b34fb"*/))
I think you must add "Scan" method before try connect.This is rule of ble architecture.Like this :
private void startScanning(final boolean enable, BluetoothAdapter mBluetoothAdapter) {
bluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
List<ScanFilter> scanFilters = new ArrayList<>();
final ScanSettings settings = new ScanSettings.Builder().build();
ScanFilter scanFilter = new ScanFilter.Builder().setServiceUuid(ParcelUuid.fromString(UUID_SERVICE)).build();
scanFilters.add(scanFilter);
bluetoothLeScanner.startScan(scanFilters, settings, scanCallback);
}
And if Ble Device is founded :
ScanCallback scanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
bluetoothDevice = result.getDevice();
Log.d(TAG, "onScanResult: bluetoothDevice.getAddress());
mScanning = false;
String adress = bluetoothDevice.getAddress();
bluetoothLeScanner.stopScan(scanCallback);
connect(bluetoothDevice);
}
Im new to Android Developement and currently working on an app that should give me the time between first time clicking a button and second time clicking the button and add it to a currently selected customer.
Current Status of App:
I established a connection to da mySql Database using Volley and a local webservice.
It works to insert my customers and time stamps to the table, but when loading times for a specific customer i get a strange result in one case. I tried debugging it but the app keeps crashing on debugging without a message. When not debugging it doesnt crash but shows weird data.
To the problem:
In my main activity called "ZeitErfassen" i have a button to get an overview of all customers display in a ListView.
I create the Listview with a custom ArrayAdapter because i want to pass my objects to the next Activity where my customers are displayed.
So onCreate of the overview of customers i create a new arraylist and fill it with all customers from my database. this list i pass to my customadapter and then set it as my adapter of the Listview.
Now, when i click on an item, i call a php script and pass the customer_id to the query to fetch all times from database where customer_id = customer_id.
Now the part where i get "strange" data...
1.(Source:ZeitErfassen;Destination:AddCustomer) I create a new customer,example xyz, in the app, data gets passed to the database.
2.(Source:ZeitErfassen;Destination:DisplayCustomer) I call my overview for all customers where the ListView is filled with data as described above. At the end ob the List I see the customer i just created,xyz.
3.Go back to Main Activity(ZeitErfassen)
4.(Source:ZeitErfassen;Destination:DisplayCustomer)I open the overview for all customers again, and it shows my last created user two times! so last entry, xyz, entry before last, xyz!
After that, i can open the view as many times as i want, the customer never gets duplicated again!
The debugger stopps after step 2.
Now when i click on the new customers, it calls the script to fetch the times by customer_id.
One of the xyz entrys display the correct times from database.
The second one, i just found out, display the times where customer_id="". In the database the value for "" is 0.
I have no clue where the second customer suddenly appears from and debugging didnt help me either -.-
When i close the app an open it again, there ist just one entry for the user that was visible twice before closing the app. It doesnt duplicate on opening view...
Here is my code..
Main Activity ZeitErfassen
public class ZeitErfassen extends AppCompatActivity {
public static LinkedList<Kunde> kunden = new LinkedList<Kunde>();
boolean running = false;
long startTime,endTime,totalTime;
private SharedPreferences app_preferences;
private SharedPreferences.Editor editor;
private TextView displayTime;
public Button startEndButton;
private ArrayAdapter<String> adapter;
private Spinner spinner;
public static Kunde selectedCustomer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_zeit_erfassen);
//Einstellungen laden
app_preferences = getApplicationContext().getSharedPreferences("MyPref", MODE_PRIVATE);
startTime= app_preferences.getLong("startTime", 0);
endTime = app_preferences.getLong("endTime", 0);
running = app_preferences.getBoolean("running", false);
displayTime = (TextView)findViewById(R.id.zeit_bei_Kunde);
displayTime.setText((CharSequence) app_preferences.getString("zeitAnzeige", "Zeit bei Kunde"));
startEndButton = (Button)findViewById(R.id.start_Timer);
startEndButton.setText((CharSequence) app_preferences.getString("timerButton", "Start Timer"));
DatabaseHelper.customerFromDatabaseToList(this);
editor = app_preferences.edit();
editor.commit();
}
public void onDestroy() {
super.onDestroy();
editor.putLong("startTime", startTime);
editor.putString("zeitAnzeige", (String) displayTime.getText());
editor.putString("timerButton", (String) startEndButton.getText());
editor.putLong("endTime", endTime);
editor.putLong("totalTime", totalTime);
editor.putBoolean("running", app_preferences.getBoolean("running", false));
editor.commit();
this.finish();
}
public void onResume() {
super.onResume();
// saveCustomers();
// createDropDown();
}
public void startTimer(View view) {
editor = app_preferences.edit();
if(running == false) {
startTime = getTime();
running = true;
editor.putLong("startTime", startTime);
startEndButton.setText("End Timer");
displayTime.setText("Zeitstoppung läuft");
editor.putString("zeitAnzeige", (String) displayTime.getText());
editor.putString("timerButton", (String) startEndButton.getText());
editor.putBoolean("running", true);
editor.commit();
} else {
setSelectedCustomer();
endTime = getTime();
editor.putLong("endTime",endTime);
totalTime = endTime - startTime;
editor.putLong("totalTime", totalTime);
displayTime.setText(formatTime(totalTime));
editor.putString("zeitAnzeige", (String) displayTime.getText());
startEndButton.setText("Start Timer");
editor.putString("timerButton", (String) startEndButton.getText());
running = false;
editor.putBoolean("running", false);
editor.commit();
DatabaseHelper.timeToDatabase(String.valueOf(selectedCustomer.getId()),formatTime(totalTime),this);
// selectedCustomer.saveTimeToCustomer(selectedCustomer, formatTimeForCustomer(totalTime));
}
}
public String formatTime(Long totalTime) {
int hours = (int) ((totalTime / (1000*60*60)) % 24);
int minutes = (int) ((totalTime / (1000*60)) % 60);
int seconds = (int) (totalTime / 1000) % 60;
String time = (String.valueOf(hours) + ":" + String.valueOf(minutes) + ":" + String.valueOf(seconds));
return time;
}
public String formatTimeForCustomer(Long totalTime) {
StringBuilder time = new StringBuilder();
Calendar cal = Calendar.getInstance();
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH);
int day = cal.get(Calendar.DAY_OF_MONTH);
time.append((String.valueOf(year) + "." + String.valueOf(month) + "." + String.valueOf(day))).append(formatTime(totalTime));
return time.toString();
}
public void neuerKunde(View view) {
Intent intent = new Intent(this, AddKunde.class);
startActivity(intent);
}
public void kundenÜbersicht(View view) {
// setSelectedCustomer();
Intent intent = new Intent(this, DisplayCustomer.class);
startActivity(intent);
}
public long getTime() {
long millis = System.currentTimeMillis();
return millis;
}
public void setSelectedCustomer() {
if(kunden.size() > 0) {
if (spinner.getSelectedItem().toString() != null) {
String tempCustomer = spinner.getSelectedItem().toString();
for (Kunde k : kunden) {
if (k.getName().equals(tempCustomer)) {
selectedCustomer = k;
}
}
}
}
}
public void createDropDown() {
/*File file = new File(this.getFilesDir(),"kunden.ser"); NOT USED BECAUSE DATABASE WORKS
if(file.exists()) {
Kunde.importFromFile(this);
}*/
if (kunden.size() > 0) {
spinner = (Spinner) findViewById(R.id.chooseCustomer);
// Create an ArrayAdapter using the string array and a default spinner layout
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, DisplayCustomer.namesOfCustomers());
// Specify the layout to use when the list of choices appears
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
// Apply the adapter to the spinner
spinner.setAdapter(adapter);
}
}
}
DisplayCustomer(Where all customers are displayed with data from Database)
public class DisplayCustomer extends AppCompatActivity {
CustomerAdapter customerAdapter;
public ArrayAdapter<String> adapterCustomerView;
private ListView listCustomerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_display_customer);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
ArrayList<Kunde> customerList = getCustomerObjects();
customerAdapter = new CustomerAdapter(this,customerList);
listCustomerView = (ListView)findViewById(R.id.list_View_Customers);
// adapterCustomerView = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, namesOfCustomers());
listCustomerView.setAdapter(customerAdapter);
openCustomerDetails();
}
public static ArrayList<String> namesOfCustomers() {
ArrayList<String> customerNames = new ArrayList<>();
if(ZeitErfassen.kunden.size() > 0 ) {
for (Kunde k : ZeitErfassen.kunden) {
customerNames.add(k.getName());
}
}
return customerNames;
}
public static ArrayList<Kunde> getCustomerObjects() {
ArrayList<Kunde> customerList = new ArrayList<>();
if(ZeitErfassen.kunden.size() > 0 ) {
for (Kunde k : ZeitErfassen.kunden) {
customerList.add(k);
}
}
return customerList;
}
public void openCustomerDetails() {
listCustomerView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Kunde kunde = new Kunde();
kunde = (Kunde)listCustomerView.getItemAtPosition(position);
Intent intent = new Intent(DisplayCustomer.this, DisplayDetailedCustomer.class);
intent.putExtra("selectedCustomerObject",(Parcelable)kunde);
startActivity(intent);
}
});
}
}
My CustomerAdapter to pass data from one intent to another.
public class CustomerAdapter extends ArrayAdapter<Kunde> {
public CustomerAdapter(Context context, ArrayList<Kunde> customerList) {
super(context,0,customerList);
}
public View getView(int position, View convertView, ViewGroup parent) {
//Data for this position
Kunde kunde = getItem(position);
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.items_customer_layout, parent, false);
}
// Lookup view for data population
TextView tvName = (TextView) convertView.findViewById(R.id.tvCustomerName);
// Populate the data into the template view using the data object
tvName.setText(kunde.getName());
// Return the completed view to render on screen
return convertView;
}
}
DatabaseHelper Class
public class DatabaseHelper {
public static RequestQueue requestQueue;
public static String host = "http://192.168.150.238/";
public static final String insertUrl = host+"insertCustomer.php";
public static final String showUrl = host+"showCustomer.php";
public static final String insertTimeUrl = host+"insertTime.php";
public static final String showTimeUrl = host+"showTimes.php";
public static void customerFromDatabaseToList(final Context context) {
//Display customer from database
requestQueue = Volley.newRequestQueue(context);
final ArrayList<String> customerNames = new ArrayList<>();
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST, showUrl, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
JSONArray customers = response.getJSONArray("customers");
if(customers.length() > 0) {
for (int i = 0; i < customers.length(); i++) {
JSONObject customer = customers.getJSONObject(i);
String customerName = customer.getString("cus_name");
String customerAddress = customer.getString("cus_address");
int customerID = Integer.valueOf(customer.getString("cus_id"));
if (customerName != null && customerAddress != null) {
try {
Kunde k = new Kunde(customerName, customerAddress, customerID);
if (!listContainsObject(k)) {
ZeitErfassen.kunden.add(k);
}
} catch (Exception e) {
showAlert("Fehler in customerFromDatabaseToListn!", "Fehler", context);
}
} else {
showAlert("Fehler in customerFromDatabaseToListn!", "Fehler", context);
}
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
}
});
requestQueue.add(jsonObjectRequest);
}
public static boolean listContainsObject(Kunde cust) {
for(Kunde k : ZeitErfassen.kunden) {
if(k.getId() == cust.getId()) {
return true;
}
}
return false;
}
public static void timeToDatabase(final String customer_id, final String time_value, final Context context) {
requestQueue = Volley.newRequestQueue(context);
StringRequest request = new StringRequest(Request.Method.POST, DatabaseHelper.insertTimeUrl, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
showAlert("Fehler","Fehler bei Verbindung zur Datenbank",context);
}
}) {
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String,String> parameters = new HashMap<String,String>();
parameters.put("customerid",customer_id);
parameters.put("timevalue",time_value);
return parameters;
}
};
requestQueue.add(request);
};
public static void showAlert(String title, String message, Context context) {
// 1. Instantiate an AlertDialog.Builder with its constructor
AlertDialog.Builder builder = new AlertDialog.Builder(context);
// 2. Chain together various setter methods to set the dialog characteristics
builder.setMessage(message)
.setTitle(title);
// 3. Get the AlertDialog from create()
AlertDialog dialog = builder.create();
}
public static ArrayList<String> timesFromDataBaseToList(final Context context,final int customer_id) {
requestQueue = Volley.newRequestQueue(context);
final String cus_id = String.valueOf(customer_id) ;
final ArrayList<String> customerTimes = new ArrayList<>();
StringRequest jsonObjectRequest = new StringRequest(Request.Method.POST, showTimeUrl, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONObject object = new JSONObject(response.toString());
JSONArray times = object.getJSONArray("customertimes");
if (times.length() > 0) {
for (int i = 0; i < times.length(); i++) {
JSONObject jsonObject = times.getJSONObject(i);
String timeValue = jsonObject.getString("time_value");
if (timeValue != null) {
customerTimes.add(timeValue);
}
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(context,"Fehler beim Holen der Zeiten",Toast.LENGTH_LONG).show();
error.printStackTrace();
}
}){
protected Map<String, String> getParams() throws AuthFailureError {
Map<String,String> parameters = new HashMap<String,String>();
parameters.put("cus_id",cus_id);
return parameters;
}
};
requestQueue.add(jsonObjectRequest);
return customerTimes;
};
}
DisplayDetailedCustomer / Display the times
public class DisplayDetailedCustomer extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_display_detailed_customer);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
Intent getCustomerParcable = getIntent();
Kunde customer = getCustomerParcable.getExtras().getParcelable("selectedCustomerObject");
TextView displayCustomerNameDetailed =(TextView) findViewById(R.id.detailedCustomerViewName);
TextView displayCustomerAddressDetailed =(TextView) findViewById(R.id.detailedCustomerAddress);
ListView timeListView = (ListView)findViewById(R.id.detailedTimeListView);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1, DatabaseHelper.timesFromDataBaseToList(this,customer.getId()));
timeListView.setAdapter(adapter);
displayCustomerNameDetailed.setText(customer.getName());
displayCustomerAddressDetailed.setText(customer.getAdresse());
}
}
Kunde Class / Customer Class with interface Parcelable
public class Kunde implements Serializable,Parcelable {
private String name;
private String adresse;
private int id;
public LinkedList<String> zeiten;
public Kunde(String name, String adresse) throws Exception{
setName(name);
setAdresse(adresse);
zeiten = new LinkedList<String>();
}
public Kunde(String name, String adresse,int id) throws Exception{
setName(name);
setAdresse(adresse);
setId(id);
zeiten = new LinkedList<String>();
}
public Kunde(){};
public void setId(int id) {
this.id = id;
}
public int getId(){
return id;
}
public void setName(String name) throws Exception {
if(name != null) {
this.name = name;
} else throw new Exception("Name ist ungueltig! in setName");
}
public void setAdresse(String adresse) throws Exception{
if(adresse != null) {
this.adresse = adresse;
}else throw new Exception("Adresse ist ungueltig! in setAdresse");
}
public String getName() {
return name;
}
public String getAdresse() {
return adresse;
}
public void saveZeit(Long totalTime) {
zeiten.add(String.valueOf(totalTime));
}
public void saveTimeToCustomer(Kunde customer,String time){
customer.zeiten.add(time);
}
//------------------------------------Parcelable Methods to pass Daata from one Intent to another----------------------------------------
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(this.id);
dest.writeString(this.name);
dest.writeString(this.adresse);
// dest.writeList(this.zeiten);
}
// this is used to regenerate your object. All Parcelables must have a CREATOR that implements these two methods
public static final Parcelable.Creator<Kunde> CREATOR = new Parcelable.Creator<Kunde>() {
public Kunde createFromParcel(Parcel in) {
return new Kunde(in);
}
public Kunde[] newArray(int size) {
return new Kunde[size];
}
};
// example constructor that takes a Parcel and gives you an object populated with it's values
private Kunde(Parcel in) {
LinkedList<String> zeiten = null;
id = in.readInt();
name = in.readString();
adresse = in.readString();
}
}
Thanks for taking your time!!
Still with the same project, this is a continuation from Run pocketSphinx and Google TTS together. I already do the revision according to the guide from Nikolay Shymyrev and do a lot of helping. But the final feature that I want implement still remains. The Google TTS run just fine now, but the recognizer have some problem.
the recognizer won't start if the Google TTS some words that quite long like
Speaker.speak("Drive mode now will be enabled. I will read your new messages for you now.");
and then my onPartialResult if condition cannot fulfilled like
if (text.equals("exit")) {
speaker.speak("yeah get in");
recognizer.cancel();
Intent i = new Intent(getApplicationContext(),PocketSphinxActivity.class);
startActivity(i);
I think the recognizer always listen since it runs in background, and then it listen the google TTS sentence that caused it won't recognize my speech afterwards. Because when I use handsfree with mic, and the sentence for speaker.Speak is just "Drive mode enabled", it recognize well my word next and execute the if condition above when I say "exit". But when the sentence is quite long like "Drive mode now will be enabled, I will read bla bla bla" it won't listen to my "exit" word.
What I want to do now is add timeout to the recognizer to timeout several momment so that it wont recognize any unnecessary sound. I want to put
startRecognition("search", timeout)
but my Eclipse won't me let do that. It gives me error. I'm Using PocketSphinx for Android 5 pre alpha.
Here's again, my code that build just to test and make sure it recognize just "exit" words
SMSReaderMain.java
public class SMSReaderMain extends Activity implements RecognitionListener {
private final int CHECK_CODE = 0x1;
private final int LONG_DURATION = 5000;
private final int SHORT_DURATION = 1200;
private Speaker speaker;
private TextView smsText;
private TextView smsSender;
private BroadcastReceiver smsReceiver;
public static final String TURNON_SR = "drive mode";
public static final String TURNOFF_SR = "ok";
public static final String DESTROY_SR = "exit";
public SpeechRecognizer recognizer;
public HashMap<String, Integer> captions;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_sms);
captions = new HashMap<String, Integer>();
new AsyncTask<Void, Void, Exception>() {
#Override
protected Exception doInBackground(Void... params) {
try {
Assets assets = new Assets(SMSReaderMain.this);
File assetDir = assets.syncAssets();
setupRecognizer(assetDir);
} catch (IOException e) {
return e;
}
return null;
}
#Override
protected void onPostExecute(Exception result) {
if (result != null) {
((TextView) findViewById(R.id.caption_text))
.setText("Failed to init recognizer " + result);
} else {
switchSearch(TURNOFF_SR);
}
}
}.execute();
//toggle = (ToggleButton)findViewById(R.id.speechToggle);
smsText = (TextView)findViewById(R.id.sms_text);
smsSender = (TextView)findViewById(R.id.sms_sender);
checkTTS();
}
private void startDriveMode(){
speaker.allow(true);
//speaker.speak(getString(R.string.start_speaking));
speaker.speak("Drive mode enabled");
}
private void checkTTS(){
Intent check = new Intent();
check.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
startActivityForResult(check, CHECK_CODE);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == CHECK_CODE){
if(resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS)
{
speaker = new Speaker(this);
}else {
Intent install = new Intent();
install.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
startActivity(install);
}
}
startDriveMode();
initializeSMSReceiver();
registerSMSReceiver();
}
private void initializeSMSReceiver(){
smsReceiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
if(bundle!=null){
Object[] pdus = (Object[])bundle.get("pdus");
for(int i=0;i<pdus.length;i++){
byte[] pdu = (byte[])pdus[i];
SmsMessage message = SmsMessage.createFromPdu(pdu);
String text = message.getDisplayMessageBody();
String sender = getContactName(message.getOriginatingAddress());
speaker.pause(LONG_DURATION);
speaker.speak("You have a new message from" + sender + "!");
speaker.pause(SHORT_DURATION);
speaker.speak(text);
smsSender.setText("Message from " + sender);
smsText.setText(text);
}
}
}
};
}
private void registerSMSReceiver() {
IntentFilter intentFilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
registerReceiver(smsReceiver, intentFilter);
}
private String getContactName(String phone){
Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phone));
String projection[] = new String[]{ContactsContract.Data.DISPLAY_NAME};
Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
if(cursor.moveToFirst()){
return cursor.getString(0);
}else {
return "unknown number";
}
}
#Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(smsReceiver);
speaker.destroy();
}
public void onPartialResult(Hypothesis hypothesis) {
//System.out.println("masuk coiii");
String text = hypothesis.getHypstr();
try {
if (text.equals("exit")) {
speaker.speak("yeah get in");
recognizer.cancel();
Intent i = new Intent(getApplicationContext(),PocketSphinxActivity.class);
startActivity(i);
}
//Intent i= null;
/**if (text.equals(TURNON_SR)) {
recognizer.cancel();
popPicture();
startDriveMode();
}
if (text.equals(TURNOFF_SR)) {
//speaker = new Speaker(this);
speaker.speak(getString(R.string.stop_speaking));
speaker.allow(false);
//popPicture2();
}
if (text.equals(DESTROY_SR)) {
recognizer.cancel();
i = new Intent(getApplicationContext(),PocketSphinxActivity.class);
startActivity(i);
onDestroy();
//popPicture2();
} **/
} catch (Exception e) {
e.printStackTrace();
}
}
public void popPicture() {
LayoutInflater inflater = getLayoutInflater();
View layout = inflater.inflate(R.layout.toast_image,(ViewGroup)
findViewById(R.id.toast_layout_id));
Toast toast = new Toast(getApplicationContext());
toast.setGravity(Gravity.CENTER_HORIZONTAL, 0, 0);
toast.setDuration(Toast.LENGTH_SHORT);
toast.setView(layout);
toast.show();
}
public void onResult(Hypothesis hypothesis) {
((TextView) findViewById(R.id.result_text)).setText("");
if (hypothesis != null) {
String text = hypothesis.getHypstr();
makeText(getApplicationContext(), text, Toast.LENGTH_SHORT).show();
}
}
public void switchSearch(String searchName) {
recognizer.stop();
recognizer.startListening(searchName);
//taro timout disini biar mic ga denger suara hp sendiri
((TextView) findViewById(R.id.caption_text)).setText(searchName);
}
public void setupRecognizer(File assetsDir) {
File modelsDir = new File(assetsDir, "models");
recognizer = defaultSetup()
.setAcousticModel(new File(modelsDir, "hmm/en-us-semi"))
.setDictionary(new File(modelsDir, "dict/cmu07a.dic"))
.setRawLogDir(assetsDir).setKeywordThreshold(1e-10f)
.getRecognizer();
recognizer.addListener(this);
// Create grammar-based searches.
// recognizer.addKeyphraseSearch(TURNOFF_SR, TURNON_SR);
//recognizer.addGrammarSearch(TURNON_SR, new File(modelsDir, "grammar/sms.gram"));
//recognizer.addGrammarSearch(TURNOFF_SR, new File(modelsDir, "grammar/sms.gram"));
//recognizer.addGrammarSearch(DESTROY_SR, new File(modelsDir, "grammar/sms.gram"));
File menuGrammar = new File(modelsDir, "grammar/sms.gram");
recognizer.addGrammarSearch(TURNOFF_SR, menuGrammar);
//recognizer.addGrammarSearch(TURNON_SR, menuGrammar);
//recognizer.addGrammarSearch(DESTROY_SR, menuGrammar);
}
#Override
public void onBeginningOfSpeech() {
// TODO Auto-generated method stub
}
#Override
public void onEndOfSpeech() {
// TODO Auto-generated method stub
}
}
Speaker.java
public class Speaker implements OnInitListener {
private TextToSpeech tts;
private boolean ready = false;
private boolean prematureSpeak = false;
private String ps;
private boolean allowed = false;
public Speaker(Context context){
tts = new TextToSpeech(context, this);
}
public boolean isAllowed(){
return allowed;
}
//public void allow(boolean allowed){
public void allow(boolean allowed){
this.allowed = allowed;
}
#Override
public void onInit(int status) {
if(status == TextToSpeech.SUCCESS){
// Change this to match your
// locale
tts.setLanguage(Locale.US);
ready = true;
if (prematureSpeak)
{
speak(ps);
prematureSpeak = false;
}
}else{
ready = false;
}
}
public void speak(String text){
// Speak only if the TTS is ready
// and the user has allowed speech
if(ready && allowed) {
HashMap<String, String> hash = new HashMap<String,String>();
hash.put(TextToSpeech.Engine.KEY_PARAM_STREAM,
String.valueOf(AudioManager.STREAM_NOTIFICATION));
tts.speak(text, TextToSpeech.QUEUE_ADD, hash);
}
else if(!ready) {
prematureSpeak = true;
ps = text;
}
}
public void pause(int duration){
tts.playSilence(duration, TextToSpeech.QUEUE_ADD, null);
}
// Free up resources
public void destroy(){
tts.shutdown();
}
public boolean isSpeaking()
{
return tts.isSpeaking();
}
}
Your code has several issues:
1) I told you to use keyword spotting mode, you are still using grammar mode
2) You need to cancel recognizer before you start voice feedback, instead of first speak then cancel
if (text.equals("exit")) {
speaker.speak("yeah get in");
recognizer.cancel();
....
you need to first cancel then speak:
if (text.equals("exit")) {
recognizer.cancel();
speaker.speak("yeah get in");
....
3) Once speaker is over you need to restart the recognizer, but there is no need to run activity again, see for details How to know when TTS is finished?
With those changes in onUtteranceEnded you start recognizer again:
public void onUtteranceCompleted(String utteranceId) {
recognizer.startSearch("search name");
}
Do not restart recognizer in onPartialResult, wait till TTS will finish.