I am working on a simple android app to do Internet-of-Things functions using the WunderBar Relayr toolkit to have sensors send data back to the android app so as to display the data. I am trying to emulate the sample temperature display app as shown in the wunderbar relayr website as well as the relayr GitHub repository so as to understand how the sensor and app communicate.
I am able to activate the master module as well as the humidity/temperature sensor, but even though the sensors work fine, the readings in the app is shown to be constant for example: 22*C. My app does not seem to be collecting the data
I can log in using my credentials, but then instead of my name being displayed, it displays another name.How can I resolve this issue?
The code is shown below.
ThermometerDemoActivity.java:
package com.vasansdomain.pavan.thermometer;
//import the Android classes we will need
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
//import the relayr SDK
import io.relayr.RelayrSdk;
import io.relayr.model.DeviceModel;
import io.relayr.model.Reading;
import io.relayr.model.Transmitter;
import io.relayr.model.TransmitterDevice;
import io.relayr.model.User;
import rx.Observable;
import rx.Observer;
import rx.Subscriber;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Func1;
import rx.schedulers.Schedulers;
import rx.subscriptions.Subscriptions;
public class ThermometerDemoActivity extends ActionBarActivity
{
private TextView mWelcomeTextView;
private TextView mTemperatureValueTextView;
private TextView mTemperatureNameTextView;
private TransmitterDevice mDevice;
private Subscription mUserInfoSubscription = Subscriptions.empty();
private Subscription mTemperatureDeviceSubscription = Subscriptions.empty();
/**
* Once the Activity has been started, the onCreate method will be called
* #param savedInstanceState
*/
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
View view = View.inflate(this, R.layout.activity_thermometer_demo, null);
mWelcomeTextView = (TextView) view.findViewById(R.id.txt_welcome);
mTemperatureValueTextView = (TextView) view.findViewById(R.id.txt_temperature_value);
mTemperatureNameTextView = (TextView) view.findViewById(R.id.txt_temperature_name);
setContentView(view);
//we use the relayr SDK to see if the user is logged in by caling the isUserLoggedIn function
if (RelayrSdk.isUserLoggedIn())
{
updateUiForALoggedInUser();
}
else
{
updateUiForANonLoggedInUser();
logIn();
}
}
/**
* When Android is ready to draw any menus it initiates the
* "prepareOptionsMenu" event, this method is caled to handle that
* event.
* #param menu
* #return
*/
#Override
public boolean onPrepareOptionsMenu(Menu menu)
{
//remove any previous items from the menu
menu.clear();
//Check to see if the user is logged in
if (RelayrSdk.isUserLoggedIn())
{
//if the user is logged in, we ask Android to draw the menu
//we defined earlier in the thermometer_demo_logged_in.xml
//file
getMenuInflater().inflate(R.menu.thermometer_demo_logged_in, menu);
}
else
{
//otherwise we return the
//thermometer_demo_not_logged_in.xml file
getMenuInflater().inflate(R.menu.thermometer_demo_not_logged_in, menu);
}
//we must return this, so that any other classes interested in
//the prepare menu event can do something.
return super.onPrepareOptionsMenu(menu);
}
/**
* When a menu item is selected, we see which item was called and
* decide what to do according to the item.
*/
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
//if the user selected login
if (item.getItemId() == R.id.action_log_in)
{
//we call the login method on the relayr SDK
logIn();
return true;
}
else if (item.getItemId() == R.id.action_log_out)
{
//otherwise we call the logout method defined later in this class
logOut();
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* The LogIn method definition
*/
private void logIn() {
RelayrSdk.logIn(this).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<User>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
Toast.makeText(ThermometerDemoActivity.this, R.string.unsuccessfully_logged_in, Toast.LENGTH_SHORT).show();
updateUiForANonLoggedInUser();
}
#Override
public void onNext(User user) {
Toast.makeText(ThermometerDemoActivity.this, R.string.successfully_logged_in, Toast.LENGTH_SHORT).show();
invalidateOptionsMenu();
updateUiForALoggedInUser();
}
});
}
/**
* Called when the user logs out
*/
private void logOut()
{
unSubscribeToUpdates();
//call the logOut method on the relayr SDK
RelayrSdk.logOut();
//call the invalidateOptionsMenu this is defined in the
//Activity class and is used to reset the menu option
invalidateOptionsMenu();
//use the Toast library to display a message to the user
Toast.makeText(this, R.string.successfully_logged_out, Toast.LENGTH_SHORT).show();
updateUiForANonLoggedInUser();
}
private void updateUiForANonLoggedInUser()
{
mTemperatureValueTextView.setVisibility(View.GONE);
mTemperatureNameTextView.setVisibility(View.GONE);
mWelcomeTextView.setText(R.string.hello_relayr);
}
private void updateUiForALoggedInUser()
{
mTemperatureValueTextView.setVisibility(View.VISIBLE);
mTemperatureNameTextView.setVisibility(View.VISIBLE);
loadUserInfo();
}
private void loadUserInfo()
{
mUserInfoSubscription = RelayrSdk.getRelayrApi().getUserInfo().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber<User>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
Toast.makeText(ThermometerDemoActivity.this, R.string.something_went_wrong, Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
#Override
public void onNext(User user) {
String hello = String.format(getString(R.string.hello), user.getName());
mWelcomeTextView.setText(hello);
loadTemperatureDevice(user);
}
});
}
private void loadTemperatureDevice(User user)
{
mTemperatureDeviceSubscription = RelayrSdk.getRelayrApi().getTransmitters(user.id).flatMap(new Func1<List<Transmitter>, Observable<List<TransmitterDevice>>>() {
#Override
public Observable<List<TransmitterDevice>> call(List<Transmitter> transmitters) {
// This is a naive implementation. Users may own many WunderBars or other
// kinds of transmitter.
if (transmitters.isEmpty())
return Observable.from(new ArrayList<List<TransmitterDevice>>());
return RelayrSdk.getRelayrApi().getTransmitterDevices(transmitters.get(0).id);
}
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber<List<TransmitterDevice>>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
Toast.makeText(ThermometerDemoActivity.this, R.string.something_went_wrong, Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
#Override
public void onNext(List<TransmitterDevice> devices) {
for (TransmitterDevice device : devices) {
if (device.model.equals(DeviceModel.TEMPERATURE_HUMIDITY.getId())) {
subscribeForTemperatureUpdates(device);
return;
}
}
}
});
}
#Override
protected void onPause()
{
super.onPause();
unSubscribeToUpdates();
}
private void unSubscribeToUpdates()
{
if (!mUserInfoSubscription.isUnsubscribed())
mUserInfoSubscription.unsubscribe();
if (!mTemperatureDeviceSubscription.isUnsubscribed())
mTemperatureDeviceSubscription.unsubscribe();
if (mDevice != null)
RelayrSdk.getWebSocketClient().unSubscribe(mDevice.id);
}
#Override
protected void onResume()
{
super.onResume();
if (RelayrSdk.isUserLoggedIn())
{
updateUiForALoggedInUser();
}
else
{
updateUiForANonLoggedInUser();
}
}
private void subscribeForTemperatureUpdates(TransmitterDevice device)
{
mDevice = device;
RelayrSdk.getWebSocketClient().subscribe(device).observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber<Reading>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
Toast.makeText(ThermometerDemoActivity.this, R.string.something_went_wrong, Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
#Override
public void onNext(Reading reading) {
if (reading.meaning.equals("temperature"))
mTemperatureValueTextView.setText(reading.value + "˚C");
}
});
}
}
ThermometerDemoApplication.java:
package com.vasansdomain.pavan.thermometer;
import android.app.Application;
import io.relayr.demo.thermometer.RelayrSdkInitializer;
public class ThermometerDemoApplication extends Application
{
#Override
public void onCreate()
{
super.onCreate();
RelayrSdkInitializer.initSdk(this);
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="#drawable/thermometer"
android:label="#string/app_name"
android:theme="#style/AppTheme"
android:name=".ThermometerDemoApplication" >
<activity
android:name=".ThermometerDemoActivity"
android:label="#string/app_name"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
activity_demo_thermometer.xml:
<LinearLayout 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:orientation="vertical"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context=".ThermometerDemoActivity"
android:background="#FFFFFF"
android:gravity="center">
<TextView
android:id="#+id/txt_welcome"
android:text="#string/hello_relayr"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000"
android:textSize="20dp" />
<TextView
android:id="#+id/txt_temperature_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="60sp"
android:paddingTop="25dp"
android:paddingBottom="25dp"/>
<TextView
android:id="#+id/txt_temperature_name"
android:text="#string/title_temperature"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="30sp"
android:layout_gravity="center"
android:paddingBottom="25dp"/>
</LinearLayout>
strings.xml
<resources>
<string name="app_name">Thermometer</string>
<string name="action_settings">Settings</string>
<string name="hello_relayr">Hello Relayr!!!</string>
<string name="hello">Hello %s!</string>
<string name="action_log_in">Log in</string>
<string name="action_log_out">Log out</string>
<string name="successfully_logged_in">You were successfully logged in!</string>
<string name="successfully_logged_out">You were successfully logged out!</string>
<string name="unsuccessfully_logged_in">There was a problem in the log in.</string>
<string name="something_went_wrong">Oops! Something went wrong</string>
<string name="title_temperature">Temperature</string>
</resources>
This is the code for the mock mode of the app:debug->java->io->relayr->demo->thermometer
package io.relayr.demo.thermometer;
import android.content.Context;
import io.relayr.RelayrSdk;
public abstract class RelayrSdkInitializer {
public static void initSdk(Context context) {
new RelayrSdk.Builder(context).inMockMode(true).build();
}
}
This is the code for the release mode of the app:release->java->io->relayr->demo->thermometer
package io.relayr.demo.thermometer;
import android.content.Context;
import io.relayr.RelayrSdk;
public class RelayrSdkInitializer {
public static void initSdk(Context context) {
new RelayrSdk.Builder(context).inMockMode(false).build(); }
}
Is the answer possibly related to tweaking the RelayrSdkInitializer class in the debug file of the app
Build a release version of the app and try again. The debug version only provides mock data.
Because if you see another name (Hugo Domenech) than you are building the app in debug mode and that's why you see mocked data.
Related
I'm stucked with this problem.
In my app I use SharedPrefManager as a singleton class, in order to keep some "session" information. In this simple example app I just save the user's name and a boolean that indicates whether or not the user is logged in to skip the login screen if already logged, or to show it if not.
When starting the app, after the splashscreen, the LoginActivity is started.
At this point, if the user has already logged in before (without logging out later, that means the boolean value of isuseradded SharedPreferences variable is true), the user is redirected to the MainActivity, otherwise he sees the login form, where he can insert username and password and make a REST API request to a remote server.
If the login is correct, the MainActivity starts and simply shows the name of the user, taken from the response JSON obtained by the remote login REST API call.
Now, here is my problem: I want to implement a simple logout feature that deletes (or changes, as in this test app) all the information stored by SharedPreferences and takes the user back to the LoginActivity.
But when I click logout, the values for SharedPreferences are updated only in MainActivity, while in LoginActivity they remain the same as before, so when the user is redirected to LoginActivity, the isusedadded shared preference is still true, and the user is redirected back to MainActivity.
But SharedPrefManager class is a singleton, so its values should be the same in every part of the app, because only one instance of it exists, so why do I have this behavior?
You can test the app by downloading the full app code here and using these credentials for login:
Username: 52346
Password: 32fjueM1 (case sensitive)
Here follows my code.
App.java:
package mypackage.sharedprefapp;
import android.app.Application;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.Volley;
public class App extends Application
{
private RequestQueue mRequestQueue;
private static App mInstance;
#Override
public void onCreate()
{
super.onCreate();
mInstance = this;
}
public static synchronized App getInstance()
{
return mInstance;
}
// This method returns the queue containing GET/POST requests
public RequestQueue getRequestQueue()
{
if(mRequestQueue == null)
{
mRequestQueue = Volley.newRequestQueue(getApplicationContext());
}
return mRequestQueue;
}
// This method adds a GET/POST request to the queue of requests
public <T> void addToRequestQueue(Request<T> req)
{
getRequestQueue().add(req);
}
}
SplashActivity.java
package mypackage.sharedprefapp;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
public class SplashActivity extends AppCompatActivity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Intent intent = new Intent(this, LoginActivity.class);
startActivity(intent);
finish();
}
}
LoginActivity.java
package mypackage.sharedprefapp;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
public class LoginActivity extends AppCompatActivity
{
private static final String TAG = "LoginActivity";
Button loginButton;
EditText userIDInput, passwordInput;
TextView loginErrorMsg, title;
LinearLayout bgLayout;
SharedPrefManager sharedPrefManager;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
sharedPrefManager = SharedPrefManager.getInstance(this);
Log.i("HERE", "LoginActivity onCreate: "+sharedPrefManager.isUserAdded());
}
#Override
protected void onResume()
{
super.onResume();
sharedPrefManager = SharedPrefManager.getInstance(this);
Log.i("HERE", "LoginActivity onResume: "+sharedPrefManager.getUserName());
// if the user is already logged in
if(sharedPrefManager.isUserAdded())
{
Log.i(TAG, "User is logged in");
// if the device is connected to the internet
if(Utils.isDeviceOnline(this))
{
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
finish();
}
// if the device is offline
else
{
Log.i(TAG, "Internet connection is not available");
}
}
// if the user is not logged in
else
{
Log.i(TAG, "User is NOT logged in");
setContentView(R.layout.activity_login);
title = (TextView) findViewById(R.id.title);
loginErrorMsg = (TextView) findViewById(R.id.login_errorText);
userIDInput = (EditText) findViewById(R.id.login_id_paziente);
passwordInput = (EditText) findViewById(R.id.login_password);
loginButton = (Button) findViewById(R.id.login_submitButton);
bgLayout = (LinearLayout) findViewById(R.id.login_parentLayout);
// Bind a custom click listener to the login button
loginButton.setOnClickListener(new LoginButtonClickListener(this));
// Bind a custom click listener to the background layout
// so that the soft keyboard is dismissed when clicking on the background
bgLayout.setOnClickListener(new LoginBackgroundClickListener());
}
}
}
LoginButtonClickListener.java
package mypackage.sharedprefapp;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import com.android.volley.AuthFailureError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
public class LoginButtonClickListener implements View.OnClickListener
{
private Context context;
private SharedPrefManager sharedPrefManager;
public LoginButtonClickListener(Context c)
{
this.context = c;
}
#Override
public void onClick(View v)
{
sharedPrefManager = SharedPrefManager.getInstance(context);
// if internet connection is available
if(Utils.isDeviceOnline(context))
{
// Verify login credentials from DB
doLogin();
}
else {}
}
// check login data with REST API
private void doLogin()
{
final String paziente_id = ((EditText)((Activity)context).findViewById(R.id.login_id_paziente)).getText().toString();
final String paziente_password = ((EditText)((Activity)context).findViewById(R.id.login_password)).getText().toString();
StringRequest stringRequest = new StringRequest
(
Request.Method.POST,
"http://www.stefanopace.net/iCAREServer/api/v1/index.php/login",
new Response.Listener<String>()
{
#Override
public void onResponse(String s)
{
try
{
JSONObject obj = new JSONObject(s);
if(!obj.getBoolean("error"))
{
String name = obj.getString("nome");
sharedPrefManager.addUser(name);
Intent intent = new Intent(context, MainActivity.class);
context.startActivity(intent);
}
else
{
Toast.makeText(context, "Error on JSON response", Toast.LENGTH_LONG).show();
}
}
catch(JSONException e)
{
e.printStackTrace();
}
}
},
new Response.ErrorListener()
{
#Override
public void onErrorResponse(VolleyError volleyError)
{
Toast.makeText(context, volleyError.getMessage(), Toast.LENGTH_LONG).show();
}
})
{
#Override
protected Map<String, String> getParams() throws AuthFailureError
{
Map<String, String> params = new HashMap<>();
params.put("id_paziente", paziente_id);
params.put("password", paziente_password);
return params;
}
};
App.getInstance().addToRequestQueue(stringRequest);
}
}
LoginBackgroundClickListener.java
package mypackage.sharedprefapp;
import android.view.View;
public class LoginBackgroundClickListener implements View.OnClickListener
{
#Override
public void onClick(View v)
{
Utils.hideSoftKeyboard(v);
}
}
MainActivity.java
package mypackage.sharedprefapp;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity
{
private static final String TAG = "MainActivity";
TextView personName;
SharedPrefManager sharedPrefManager;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
sharedPrefManager = SharedPrefManager.getInstance(this);
setContentView(R.layout.activity_main);
personName = (TextView) findViewById(R.id.person_name);
Log.i(TAG, "Value: "+sharedPrefManager.isUserAdded());
personName.setText(sharedPrefManager.getUserName());
}
#Override
protected void onResume()
{
super.onResume();
sharedPrefManager = SharedPrefManager.getInstance(this);
Log.w("MainActivity", "onResume");
}
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.mainmenu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch(item.getItemId())
{
// Logout button has been pressed
case R.id.logout_action:
{
Log.i("Logout pressed", "Logout button has been pressed!");
final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
alertDialogBuilder.setMessage("Are you sure you want to logout?");
alertDialogBuilder.setPositiveButton
(
"Yes",
new DialogInterface.OnClickListener()
{
#Override
public void onClick(DialogInterface arg0, int arg1)
{
boolean success = sharedPrefManager.removeDataFromSharedPreference();
// if the operation is OK
if(success)
{
// go to the login activity
Intent intent = new Intent(MainActivity.this, LoginActivity.class);
startActivity(intent);
finish();
}
else
{
Toast.makeText(getApplicationContext(), "Error during logout", Toast.LENGTH_LONG).show();
}
}
}
);
alertDialogBuilder.setNegativeButton
(
"No",
new DialogInterface.OnClickListener()
{
#Override
public void onClick(DialogInterface arg0, int arg1)
{}
}
);
AlertDialog alertDialog = alertDialogBuilder.create();
alertDialog.show();
return true;
}
}
return super.onOptionsItemSelected(item);
}
}
SharedPrefManager.java
package mypackage.sharedprefapp;
import android.content.Context;
import android.content.SharedPreferences;
public final class SharedPrefManager
{
private static final String TAG = "SharedPrefManager";
private SharedPreferences sharedPreferences;
private SharedPreferences.Editor editor;
private static SharedPrefManager mInstance;
private static final String SHARED_PREF = "sharedprefs";
private static final String KEY_IS_USER_ADDED = "isuseradded";
public static final String KEY_USER_NAME = "username";
private SharedPrefManager(Context context)
{
sharedPreferences = context.getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE);
editor = sharedPreferences.edit();
sharedPreferences.registerOnSharedPreferenceChangeListener(new LocalSharedPreferencesChangeListener());
}
public static SharedPrefManager getInstance(Context context)
{
if(mInstance == null)
{
mInstance = new SharedPrefManager(context);
}
return mInstance;
}
// add an user to the shared preferences
public boolean addUser(String name)
{
editor.putString(KEY_USER_NAME, name);
editor.putBoolean(KEY_IS_USER_ADDED, true);
return editor.commit();
}
public boolean removeDataFromSharedPreference()
{
editor.putString(KEY_USER_NAME, "HELLO");
editor.putBoolean(KEY_IS_USER_ADDED, false);
return editor.commit();
}
public String getUserName()
{
return sharedPreferences.getString(KEY_USER_NAME, "");
}
public boolean isUserAdded()
{
return sharedPreferences.getBoolean(KEY_IS_USER_ADDED, false);
}
}
Utils.java
package mypackage.sharedprefapp;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.v7.app.AlertDialog;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
public class Utils
{
public static void hideSoftKeyboard(View view)
{
InputMethodManager inputMethodManager = (InputMethodManager) view.getContext().getSystemService(Activity.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
// This method checks if the device is connected to the Internet
public static boolean isDeviceOnline(final Context context)
{
final ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if(connectivityManager != null)
{
final NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
boolean isOnline = (networkInfo != null && networkInfo.isConnectedOrConnecting());
if(!isOnline)
{
AlertDialog.Builder alertDialog = new AlertDialog.Builder(context);
alertDialog.setCancelable(false);
alertDialog.setTitle("Error");
alertDialog.setMessage("Internet is not available");
alertDialog.setPositiveButton("Try again", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
// Reload the Activity
Intent intent = ((Activity) context).getIntent();
((Activity) context).finish();
context.startActivity(intent);
}
});
alertDialog.show();
}
return isOnline;
}
return false;
}
}
LocalSharedPreferencesChangeListener
package mypackage.sharedprefapp;
import android.content.SharedPreferences;
import android.util.Log;
public class LocalSharedPreferencesChangeListener implements SharedPreferences.OnSharedPreferenceChangeListener
{
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)
{
Log.i("HERE", key);
}
}
activity_login.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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context=".LoginActivity"
android:padding="0dp">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/scrollView"
android:layout_gravity="center_horizontal">
<LinearLayout
android:id="#+id/login_parentLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:clickable="true">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#mipmap/ic_launcher"
android:layout_gravity="center_horizontal"
android:layout_marginTop="50dp"
android:layout_marginBottom="30dp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/app_name"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal"
android:layout_marginBottom="30dp"
android:singleLine="false"
android:padding="5dp"
android:textSize="30sp" />
<EditText
android:id="#+id/login_id_paziente"
android:layout_width="match_parent"
android:layout_height="40dp"
android:inputType="number"
android:ems="10"
android:hint="Username"
android:textColor="#android:color/black"
android:textColorHint="#android:color/darker_gray"
android:singleLine="true"
android:minLines="1"
android:gravity="center_horizontal"
android:layout_marginLeft="50dp"
android:layout_marginRight="50dp"
android:focusableInTouchMode="true"
android:focusable="true" />
<EditText
android:id="#+id/login_password"
android:layout_width="match_parent"
android:layout_height="40dp"
android:hint="Password"
android:textColorHint="#android:color/darker_gray"
android:inputType="textPassword"
android:ems="10"
android:textColor="#android:color/black"
android:maxLines="1"
android:singleLine="true"
android:layout_marginTop="20dp"
android:gravity="center_horizontal"
android:layout_marginLeft="50dp"
android:layout_marginRight="50dp"
android:focusableInTouchMode="true"
android:focusable="true" />
<TextView
android:id="#+id/login_errorText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Login error"
android:textColor="#android:color/holo_red_dark"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal"
android:singleLine="false"
android:padding="5dp"
android:textSize="20sp"
android:layout_margin="10dp"
android:visibility="invisible" />
<Button
android:id="#+id/login_submitButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Login"
android:textSize="20sp"
android:layout_marginLeft="50dp"
android:layout_marginRight="50dp" />
</LinearLayout>
</ScrollView>
</LinearLayout>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<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="mypackage.sharedprefapp.MainActivity">
<TextView
android:id="#+id/person_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:textSize="25sp"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true" />
</RelativeLayout>
splashscreen.xml (in drawable resources folder)
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#android:color/holo_green_dark"/>
<item>
<bitmap
android:gravity="center"
android:src="#mipmap/ic_launcher"/>
</item>
</layer-list>
mainmenu.xml (in res/menu resource folder)
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="#+id/logout_action"
android:title="Logout"
app:showAsAction="always" />
</menu>
styles.xml
<resources>
...
<style name="SplashTheme" parent="Theme.AppCompat.NoActionBar">
<item name="android:windowBackground">#drawable/splashscreen</item>
</style>
</resources>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="mypackage.sharedprefapp">
<!-- Needs internet to connect to Google Services -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- Permission to check internet connection state -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:name=".App"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".SplashActivity"
android:label="#string/app_name"
android:screenOrientation="portrait"
android:theme="#style/AppTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:screenOrientation="portrait"
android:theme="#style/AppTheme" />
<activity
android:name=".LoginActivity"
android:label="#string/app_name"
android:process=":other_process"
android:screenOrientation="portrait"
android:theme="#style/AppTheme">
<intent-filter>
<action android:name="android.intent.action.LOGIN_ACTION" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>
build.gradle (Module: app)
dependencies {
...
compile 'com.android.volley:volley:1.0.0'
}
Thank you!
Just call editor.clear();
and editor.commit();
is enough to delete all data from shared preference.
Because onResume, you keep on instantiating a new SharedPrefManager
sharedPrefManager = new SharedPrefManager(this);
Modify your SharedPrefManager so that it only gives one instance at all times OR make sure that you are referring to the same object when you return to LoginActivity.
SharedPreferences is permanent storage, you can clear
SharedPreferences.Editor.clear().commit();
alternate solution
you want once app close clear entire values,try Application singleton class
#Ciammarica you can call this code on click of Logout button, hope this can help you..you can set in logout button boolean value false..
SessionManager.setUserLoggedIn(YourActivity.this, false); SessionManager.clearAppCredential(YourActivity.this);
I Changed my code in order to have only one instance of SharedPrefManager class.
This is my App singleton class:
public class App extends Application
{
private static App mInstance;
private SharedPrefManager sharedPrefManager;
#Override
public void onCreate() {
super.onCreate();
mInstance = this;
sharedPrefManager = new SharedPrefManager(this);
}
public SharedPrefManager getSharedPrefManager(){
return sharedPrefManager;
}
public static synchronized App getInstance(){
return mInstance;
}
}
Then from other classes I get the instance by calling
SharedPrefManager sharedPrefManager = App.getInstance().getSharedPrefManager();
Now, with this change, the onSharedPreferenceChanged() event is triggered only once, so this is better than before, but the "delayed" behavior is still there... I mean, even if I use editor.clear(); and editor.commit(); methods, the values are updated but I can see them only if I close and open the app again.
I found the problem myself... It didn't like the sharedPrefManager.removeDataFromSharedPreference(); method to be called from inside new DialogInterface.OnClickListener()
I took it in another part of the code and it worked.
I want to create app using Android Studio Login Activity. It said that #+id/login in attribute imeActionId is not a valid integer. What happened? I didn't change anything.It's 'android:imeActionId="#+id/login"' by default.
http://i.stack.imgur.com/ow5b8.png
My source code.
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.com.login" >
<!-- To auto-complete the email text field in the login form with the user's emails -->
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.READ_PROFILE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".LoginActivity"
android:label="#string/app_name"
android:windowSoftInputMode="adjustResize|stateVisible" >
</activity>
</application>
</manifest>
LoginActivity
package android.com.login;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.ContentResolver;
import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.inputmethod.EditorInfo;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
/**
* A login screen that offers login via email/password.
*/
public class LoginActivity extends Activity implements LoaderCallbacks<Cursor> {
/**
* A dummy authentication store containing known user names and passwords.
* TODO: remove after connecting to a real authentication system.
*/
private static final String[] DUMMY_CREDENTIALS = new String[]{
"foo#example.com:hello", "bar#example.com:world"
};
/**
* Keep track of the login task to ensure we can cancel it if requested.
*/
private UserLoginTask mAuthTask = null;
// UI references.
private AutoCompleteTextView mEmailView;
private EditText mPasswordView;
private View mProgressView;
private View mLoginFormView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
// Set up the login form.
mEmailView = (AutoCompleteTextView) findViewById(R.id.email);
populateAutoComplete();
mPasswordView = (EditText) findViewById(R.id.password);
mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {
if (id == R.id.login || id == EditorInfo.IME_NULL) {
attemptLogin();
return true;
}
return false;
}
});
Button mEmailSignInButton = (Button) findViewById(R.id.email_sign_in_button);
mEmailSignInButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
attemptLogin();
}
});
mLoginFormView = findViewById(R.id.login_form);
mProgressView = findViewById(R.id.login_progress);
}
private void populateAutoComplete() {
getLoaderManager().initLoader(0, null, this);
}
/**
* Attempts to sign in or register the account specified by the login form.
* If there are form errors (invalid email, missing fields, etc.), the
* errors are presented and no actual login attempt is made.
*/
public void attemptLogin() {
if (mAuthTask != null) {
return;
}
// Reset errors.
mEmailView.setError(null);
mPasswordView.setError(null);
// Store values at the time of the login attempt.
String email = mEmailView.getText().toString();
String password = mPasswordView.getText().toString();
boolean cancel = false;
View focusView = null;
// Check for a valid password, if the user entered one.
if (!TextUtils.isEmpty(password) && !isPasswordValid(password)) {
mPasswordView.setError(getString(R.string.error_invalid_password));
focusView = mPasswordView;
cancel = true;
}
// Check for a valid email address.
if (TextUtils.isEmpty(email)) {
mEmailView.setError(getString(R.string.error_field_required));
focusView = mEmailView;
cancel = true;
} else if (!isEmailValid(email)) {
mEmailView.setError(getString(R.string.error_invalid_email));
focusView = mEmailView;
cancel = true;
}
if (cancel) {
// There was an error; don't attempt login and focus the first
// form field with an error.
focusView.requestFocus();
} else {
// Show a progress spinner, and kick off a background task to
// perform the user login attempt.
showProgress(true);
mAuthTask = new UserLoginTask(email, password);
mAuthTask.execute((Void) null);
}
}
private boolean isEmailValid(String email) {
//TODO: Replace this with your own logic
return email.contains("#");
}
private boolean isPasswordValid(String password) {
//TODO: Replace this with your own logic
return password.length() > 4;
}
/**
* Shows the progress UI and hides the login form.
*/
#TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
public void showProgress(final boolean show) {
// On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow
// for very easy animations. If available, use these APIs to fade-in
// the progress spinner.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
mLoginFormView.animate().setDuration(shortAnimTime).alpha(
show ? 0 : 1).setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
}
});
mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
mProgressView.animate().setDuration(shortAnimTime).alpha(
show ? 1 : 0).setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
}
});
} else {
// The ViewPropertyAnimator APIs are not available, so simply show
// and hide the relevant UI components.
mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
}
}
#Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
return new CursorLoader(this,
// Retrieve data rows for the device user's 'profile' contact.
Uri.withAppendedPath(ContactsContract.Profile.CONTENT_URI,
ContactsContract.Contacts.Data.CONTENT_DIRECTORY), ProfileQuery.PROJECTION,
// Select only email addresses.
ContactsContract.Contacts.Data.MIMETYPE +
" = ?", new String[]{ContactsContract.CommonDataKinds.Email
.CONTENT_ITEM_TYPE},
// Show primary email addresses first. Note that there won't be
// a primary email address if the user hasn't specified one.
ContactsContract.Contacts.Data.IS_PRIMARY + " DESC");
}
#Override
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
List<String> emails = new ArrayList<String>();
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
emails.add(cursor.getString(ProfileQuery.ADDRESS));
cursor.moveToNext();
}
addEmailsToAutoComplete(emails);
}
#Override
public void onLoaderReset(Loader<Cursor> cursorLoader) {
}
private interface ProfileQuery {
String[] PROJECTION = {
ContactsContract.CommonDataKinds.Email.ADDRESS,
ContactsContract.CommonDataKinds.Email.IS_PRIMARY,
};
int ADDRESS = 0;
int IS_PRIMARY = 1;
}
private void addEmailsToAutoComplete(List<String> emailAddressCollection) {
//Create adapter to tell the AutoCompleteTextView what to show in its dropdown list.
ArrayAdapter<String> adapter =
new ArrayAdapter<String>(LoginActivity.this,
android.R.layout.simple_dropdown_item_1line, emailAddressCollection);
mEmailView.setAdapter(adapter);
}
/**
* Represents an asynchronous login/registration task used to authenticate
* the user.
*/
public class UserLoginTask extends AsyncTask<Void, Void, Boolean> {
private final String mEmail;
private final String mPassword;
UserLoginTask(String email, String password) {
mEmail = email;
mPassword = password;
}
#Override
protected Boolean doInBackground(Void... params) {
// TODO: attempt authentication against a network service.
try {
// Simulate network access.
Thread.sleep(2000);
} catch (InterruptedException e) {
return false;
}
for (String credential : DUMMY_CREDENTIALS) {
String[] pieces = credential.split(":");
if (pieces[0].equals(mEmail)) {
// Account exists, return true if the password matches.
return pieces[1].equals(mPassword);
}
}
// TODO: register the new account here.
return true;
}
#Override
protected void onPostExecute(final Boolean success) {
mAuthTask = null;
showProgress(false);
if (success) {
finish();
} else {
mPasswordView.setError(getString(R.string.error_incorrect_password));
mPasswordView.requestFocus();
}
}
#Override
protected void onCancelled() {
mAuthTask = null;
showProgress(false);
}
}
}
activity_login.xml
<LinearLayout 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:gravity="center_horizontal"
android:orientation="vertical" 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=".LoginActivity">
<!-- Login progress -->
<ProgressBar android:id="#+id/login_progress" style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="8dp" android:visibility="gone" />
<ScrollView android:id="#+id/login_form" android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout android:id="#+id/email_login_form" android:layout_width="match_parent"
android:layout_height="wrap_content" android:orientation="vertical">
<AutoCompleteTextView android:id="#+id/email" android:layout_width="match_parent"
android:layout_height="wrap_content" android:hint="#string/prompt_email"
android:inputType="textEmailAddress" android:maxLines="1"
android:singleLine="true" />
<EditText android:id="#+id/password" android:layout_width="match_parent"
android:layout_height="wrap_content" android:hint="#string/prompt_password"
android:imeActionId="#+id/login"
android:imeActionLabel="#string/action_sign_in_short"
android:imeOptions="actionUnspecified" android:inputType="textPassword"
android:maxLines="1" android:singleLine="true" />
<Button android:id="#+id/email_sign_in_button" style="?android:textAppearanceSmall"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_marginTop="16dp" android:text="#string/action_sign_in"
android:textStyle="bold" />
</LinearLayout>
</ScrollView>
</LinearLayout>
The result: http://i.stack.imgur.com/C49NT.png
LoginActivity requires minSDK version 9. Please check your minSDK version in AndroidManifest file. Also check the same in gradle.build file.
Im trying to add text into a listview within a fragment but i keep getting an error: cannot find symbol method setListAdapter(ArrayAdapter).
I'm using this tutorial as reference but it only shows how to do it within a activity : http://wptrafficanalyzer.in/blog/dynamically-add-items-to-listview-in-android/
Im trying to move this over to a fragment. Can anyone help please i would highly appreciate it? heres my code :
MainActivity:
import android.app.Activity;
import android.os.Bundle;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
import com.example.fragments.DeleteDialogueFragment;
import com.example.PeopleFragment;
public class MainActivity extends Activity implements PeopleFragment.PeopleFragmentListener, DeleteDialogueFragment.DeleteDialogueListener {
private final String TAG = "MAINACTIVITY";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.add(R.id.container, new PeopleFragment())
.commit();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
//INTERFACE METHODS
public void deleteCharacter(){
PeopleFragment peopleFragment = (PeopleFragment) getFragmentManager().findFragmentById(R.id.container);
peopleFragment.deleteCharacter();
}
}
PeopleFragment :
import android.app.Activity;
import android.app.DialogFragment;
import android.app.Fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.ActionMode;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import com.example.actionbardemo.R;
import java.util.ArrayList;
import java.util.Arrays;
public class PeopleFragment extends Fragment{
private final String TAG = "PEOPLEFRAGMENT";
private PeopleFragmentListener mListener;
private ArrayAdapter<String> mPeopleAdapter;
private ActionMode mActionMode;
private int mPersonSelected = -1;
/** Items entered by the user is stored in this ArrayList variable */
private ArrayList<String> pList = new ArrayList<String>();
public interface PeopleFragmentListener {
}
public static PeopleFragment newInstance() {
PeopleFragment fragment = new PeopleFragment();
return fragment;
}
public PeopleFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ArrayList<String> people = new ArrayList<String>(Arrays.asList(getResources().getStringArray(R.array.people)));
mPeopleAdapter = new ArrayAdapter<String>(getActivity(),android.R.layout.simple_list_item_1,people);
// Reference to the button of the layout main.xml
Button btn = (Button) getView().findViewById(R.id.btnAdd);
// Defining a click event listener for the button "Add"
View.OnClickListener listener = new View.OnClickListener() {
#Override
public void onClick(View v) {
EditText edit = (EditText) getView().findViewById(R.id.txtItem);
pList.add(edit.getText().toString());
edit.setText("");
mPeopleAdapter.notifyDataSetChanged();
}
};
// Setting the event listener for the add button
btn.setOnClickListener(listener);
// Setting the adapter to the ListView
setListAdapter(mPeopleAdapter);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
ListView peopleList = (ListView) rootView.findViewById(R.id.peopleList);
peopleList.setAdapter(mPeopleAdapter);
peopleList.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
if(mActionMode != null){
return false;
}
mPersonSelected = position;
mActionMode = getActivity().startActionMode(mActionModeCallback);
return true;
}
});
return rootView;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (PeopleFragmentListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement PeopleFragmentListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
//INTERFACE METHODS
public void deleteCharacter(){
mPeopleAdapter.remove(mPeopleAdapter.getItem(mPersonSelected));
mPeopleAdapter.notifyDataSetChanged();
}
public String getToDelete(){
return mPeopleAdapter.getItem(mPersonSelected);
}
//CONTEXTUAL ACTION BAR CALLBACK
private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
// Called when the action mode is created; startActionMode() was called
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
// Inflate a menu resource providing context menu items
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.peoplemenu, menu);
return true;
}
// Called each time the action mode is shown. Always called after onCreateActionMode, but
// may be called multiple times if the mode is invalidated.
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false; // Return false if nothing is done
}
// Called when the user selects a contextual menu item
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.peopleDelete:
Log.i(TAG,mPeopleAdapter.getItem(mPersonSelected));
DialogFragment dialog = new DeleteDialogueFragment();
Bundle args = new Bundle();
args.putString("name",mPeopleAdapter.getItem(mPersonSelected));
dialog.setArguments(args);
dialog.show(getActivity().getFragmentManager(), "DeleteDiaglogueFragment");
mode.finish();
return true;
default:
return false;
}
}
// Called when the user exits the action mode
#Override
public void onDestroyActionMode(ActionMode mode) {
mActionMode = null;
}
};
}
activity_main.xml (layout):
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
tools:ignore="MergeRootFrame" />
fragment_main.xml (layout):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:id="#+id/txtItem"
android:layout_width="240dp"
android:layout_height="wrap_content"
android:inputType="text"
android:hint="#string/hintTxtItem"/>
<Button
android:id="#+id/btnAdd"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/lblBtnAdd"
android:layout_toRightOf="#id/txtItem"/>
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/peopleList"
android:layout_gravity="center_horizontal" />
</LinearLayout>
strings.xml(values):
<string name="app_name">ActionBarDemo</string>
<string name="action_settings">Settings</string>
<string name="hintTxtItem">Enter an item here ...</string>
<string name="lblBtnAdd">Add Item</string>
<string name="txtEmpty">List is empty</string>
<string name="delete_confirm">Are you sure you want to delete</string>
<string name="delete">Delete</string>
<string name="cancel">Cancel</string>
<string-array name="people">
<item>person 1</item>
<item>person 2</item>
<item>person 3</item>
<item>person 4</item>
<item>person 5</item>
<item>person 6</item>
</string-array>
Can u provide me the simple code for scanning the nearby BLE devices and list it by device name and MAC ID. I tried this using sample code provided in http://developer.android.com/guide/topics/connectivity/bluetooth-le.html. But didn't work, any reference link or ideas since i am new to BLE app.
This example is based on the developers web you posted and works great for me. This is the code:
DeviceScanActivity.class
package com.example.android.bluetoothlegatt;
import android.app.Activity;
import android.app.ListActivity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
public class DeviceScanActivity extends ListActivity {
private LeDeviceListAdapter mLeDeviceListAdapter;
private BluetoothAdapter mBluetoothAdapter;
private boolean mScanning;
private Handler mHandler;
private static final int REQUEST_ENABLE_BT = 1;
// Stops scanning after 10 seconds.
private static final long SCAN_PERIOD = 10000;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActionBar().setTitle(R.string.title_devices);
mHandler = new Handler();
// 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 bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.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;
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
if (!mScanning) {
menu.findItem(R.id.menu_stop).setVisible(false);
menu.findItem(R.id.menu_scan).setVisible(true);
menu.findItem(R.id.menu_refresh).setActionView(null);
} else {
menu.findItem(R.id.menu_stop).setVisible(true);
menu.findItem(R.id.menu_scan).setVisible(false);
menu.findItem(R.id.menu_refresh).setActionView(
R.layout.actionbar_indeterminate_progress);
}
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_scan:
mLeDeviceListAdapter.clear();
scanLeDevice(true);
break;
case R.id.menu_stop:
scanLeDevice(false);
break;
}
return true;
}
#Override
protected void onResume() {
super.onResume();
// Ensures Bluetooth is enabled on the device. If Bluetooth is not currently enabled,
// fire an intent to display a dialog asking the user to grant permission to enable it.
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
// Initializes list view adapter.
mLeDeviceListAdapter = new LeDeviceListAdapter();
setListAdapter(mLeDeviceListAdapter);
scanLeDevice(true);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// User chose not to enable Bluetooth.
if (requestCode == REQUEST_ENABLE_BT && resultCode == Activity.RESULT_CANCELED) {
finish();
return;
}
super.onActivityResult(requestCode, resultCode, data);
}
#Override
protected void onPause() {
super.onPause();
scanLeDevice(false);
mLeDeviceListAdapter.clear();
}
private void scanLeDevice(final boolean enable) {
if (enable) {
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
invalidateOptionsMenu();
}
}, SCAN_PERIOD);
mScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
invalidateOptionsMenu();
}
// Adapter for holding devices found through scanning.
private class LeDeviceListAdapter extends BaseAdapter {
private ArrayList<BluetoothDevice> mLeDevices;
private LayoutInflater mInflator;
public LeDeviceListAdapter() {
super();
mLeDevices = new ArrayList<BluetoothDevice>();
mInflator = DeviceScanActivity.this.getLayoutInflater();
}
public void addDevice(BluetoothDevice device) {
if(!mLeDevices.contains(device)) {
mLeDevices.add(device);
}
}
public BluetoothDevice getDevice(int position) {
return mLeDevices.get(position);
}
public void clear() {
mLeDevices.clear();
}
#Override
public int getCount() {
return mLeDevices.size();
}
#Override
public Object getItem(int i) {
return mLeDevices.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder viewHolder;
// General ListView optimization code.
if (view == null) {
view = mInflator.inflate(R.layout.listitem_device, null);
viewHolder = new ViewHolder();
viewHolder.deviceAddress = (TextView) view.findViewById(R.id.device_address);
viewHolder.deviceName = (TextView) view.findViewById(R.id.device_name);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
BluetoothDevice device = mLeDevices.get(i);
final String deviceName = device.getName();
if (deviceName != null && deviceName.length() > 0)
viewHolder.deviceName.setText(deviceName);
else
viewHolder.deviceName.setText(R.string.unknown_device);
viewHolder.deviceAddress.setText(device.getAddress());
return view;
}
}
// 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();
}
});
}
};
static class ViewHolder {
TextView deviceName;
TextView deviceAddress;
}
}
The custom layout for the Listview listitem_device.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView android:id="#+id/device_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="24dp"/>
<TextView android:id="#+id/device_address"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="12dp"/>
</LinearLayout>
The progress bar on scanning actionbar_indeterminate_progress.xml :
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_width="56dp"
android:minWidth="56dp">
<ProgressBar android:layout_width="32dp"
android:layout_height="32dp"
android:layout_gravity="center"/>
</FrameLayout>
The menu layout main.xml :
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#+id/menu_refresh"
android:checkable="false"
android:orderInCategory="1"
android:showAsAction="ifRoom"/>
<item android:id="#+id/menu_scan"
android:title="#string/menu_scan"
android:orderInCategory="100"
android:showAsAction="ifRoom|withText"/>
<item android:id="#+id/menu_stop"
android:title="#string/menu_stop"
android:orderInCategory="101"
android:showAsAction="ifRoom|withText"/>
</menu>
The strings layout strings.xml :
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="ble_not_supported">BLE is not supported</string>
<string name="error_bluetooth_not_supported">Bluetooth not supported.</string>
<string name="unknown_device">Unknown device</string>
<!-- Menu items -->
<string name="menu_connect">Connect</string>
<string name="menu_disconnect">Disconnect</string>
<string name="menu_scan">Scan</string>
<string name="menu_stop">Stop</string>
</resources>
And the manifest AndroidManifest.xml :
<?xml version="1.0" encoding="UTF-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.bluetoothlegatt"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="18"
android:targetSdkVersion="19"/>
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<application android:label="#string/app_name"
android:icon="#drawable/ic_launcher"
android:theme="#android:style/Theme.Holo.Light">
<activity android:name=".DeviceScanActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
I think this is all. If I missed anything let me now and I fix it. Hope it helps!!
(Bluetooth LE quite sucks in Android yet :D... needs and update fast!)
UPDATE:
Check the full example of BLE scan and connection in GitHub:
https://github.com/kodartcha/BLEDeviceScanSample
this is quite old question, but for future readers I just want to propose to check out official source codes provided by Bluetooth SIG:
Application Accelerator
There are small, easy to understand and documented apps for most mobile platforms (Android, iOS, Windows Phone and more) + some materials/tutorials. If you want to start playing with BLE this is the best starting point in my opinion.
Everything is free, but you need to register on the website. As far as I remember there is maybe 1-3 emails by year, all connected with new tools for Bluetooth development.
Darek
I am using two different Layouts for same Activity, On orientation change the activity state is not maintained. Please suggest how to do that?
You can easily store your "activity state" using onSavedInstanceState. For example:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(saveInstanceState != null) {
if(savedInstanceState.getBoolean("running") == true) {
// previously is running
} else {
// previously not running
}
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if(condition) {
outState.putBoolean("running", true);
}
}
You seem to do some work in an AsyncTask and then you're changing the orientation.
Move the task you're doing from AsyncTask in an IntentService. Once the job is executed, send a broadcast with the result. In your activity, register a BroadcastReceiver in onCreate and de-register it in onDestroy.
That receiver will handle the result of your operation. You could also send from IntentService some intermediary data/progress update that can be received and processed by the same Receiver.
EDIT: to show some code.
The first search result on Google for IntentService tutorial. But I would strongly recommend reading more about Services. Also Vogella has a nice article about this.
About BroadcastReceivers.
If you want something to get you started here's a sample project I built in 15 mins:
The activity:
package com.adip.droid.sampleandroid;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.content.LocalBroadcastManager;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;
public class FrontActivity extends FragmentActivity {
private TextView labelData;
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WorkerService.WORK_PROGRESS_ACTION.equals(action)) {
publishProgress(intent.getStringExtra(WorkerService.WORK_KEY_PROGRESS));
} else if (WorkerService.WORK_END_ACTION.equals(action)) {
workInProgress = false;
publishResult(intent.getStringExtra(WorkerService.WORK_KEY_RESULT));
}
}
};
protected void publishProgress(String data) {
showMessage(data);
}
protected void publishResult(String data) {
showMessage(data);
}
private void showMessage(String data) {
labelData.setText(data);
}
/**
* Maybe you need this in order to not start the service once you have an ongoing job ...
* */
private boolean workInProgress;
#Override
protected void onCreate(Bundle instanceState) {
super.onCreate(instanceState);
setContentView(R.layout.front_layout);
if (instanceState != null) {
workInProgress = instanceState.getBoolean("WORK_IN_PROGRESS", false);
}
labelData = (TextView) findViewById(R.id.labelData);
findViewById(R.id.btnWorker).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
doTheJob();
}
});
IntentFilter filter = new IntentFilter(WorkerService.WORK_END_ACTION);
filter.addAction(WorkerService.WORK_PROGRESS_ACTION);
LocalBroadcastManager.getInstance(this).registerReceiver(receiver, filter);
}
protected void doTheJob() {
if (workInProgress) {
return;
}
Intent serviceIntent = new Intent(this, WorkerService.class);
serviceIntent.setAction(WorkerService.WORK_START_ACTION);
startService(serviceIntent);
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean("WORK_IN_PROGRESS", workInProgress);
}
#Override
protected void onDestroy() {
super.onDestroy();
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
}
}
its layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="#+id/btnWorker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Start the work" />
<TextView
android:id="#+id/labelData"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/btnWorker"
android:layout_centerHorizontal="true"
android:layout_marginBottom="35dp"
android:freezesText="true"
android:text="No data yet"
android:textAppearance="?android:attr/textAppearanceMedium" />
</RelativeLayout>
and the IntentService:
package com.adip.droid.sampleandroid;
import android.app.IntentService;
import android.content.Intent;
import android.support.v4.content.LocalBroadcastManager;
public class WorkerService extends IntentService {
public static final String WORK_START_ACTION = "WORK_START_ACTION";
public static final String WORK_END_ACTION = "WORK_END_ACTION";
public static final String WORK_KEY_RESULT = "WORK_KEY_RESULT";
public static final String WORK_PROGRESS_ACTION = "WORK_PROGRESS_ACTION";
public static final String WORK_KEY_PROGRESS = "WORK_KEY_PROGRESS";
public WorkerService() {
super("WorkerService");
}
#Override
protected void onHandleIntent(Intent intent) {
if (WORK_START_ACTION.equals(intent.getAction())) {
startProgress();
}
}
private void startProgress() {
publishProgress("Starting the job");
synchronized (this) {
try {
wait(2500);
} catch (InterruptedException ignored) {
}
}
publishProgress("Progress Point A");
synchronized (this) {
try {
wait(2500);
} catch (InterruptedException ignored) {
}
}
publishJobDone();
}
public void publishProgress(String data) {
Intent progressIntent = new Intent(WORK_PROGRESS_ACTION);
progressIntent.putExtra(WORK_KEY_PROGRESS, data);
LocalBroadcastManager.getInstance(this).sendBroadcast(progressIntent);
}
public void publishJobDone() {
Intent progressIntent = new Intent(WORK_END_ACTION);
progressIntent.putExtra(WORK_KEY_RESULT, "Job done!");
LocalBroadcastManager.getInstance(this).sendBroadcast(progressIntent);
}
}
Also don't forget to update your manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.adip.droid.sampleandroid"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".FrontActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".WorkerService"
android:exported="false" >
</service>
</application>
</manifest>