I recently started working with android and I wanted to program my own Pedometer app that counts how many steps I have taken. Sadly somehow the onSensorChanged() method isn't called. I made sure my phone has the sensor and I also made sure that everything else is working fine (registering a listener, creating a SensorManager and a Sensor) and everything seems to be working fine. I have als added
uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" in the android manifest since another post stated this is needed. Here is my code:
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.util.List;
public class MainActivity extends AppCompatActivity implements SensorEventListener{
Button btnReset;
private SensorManager sensorManager;
private Sensor stepSensor;
private boolean isStepSensorAvailable;
private TextView txtSteps, txtCheck;
private int stepCounter;
private List<Sensor> deviceSensors; //bugfixing
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initialize();
if(sensorManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR) != null)
{
stepSensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR);
txtCheck.setText("Sensor was found, stepsensor is now " + stepSensor.getName());
isStepSensorAvailable = true;
}
else
{
txtSteps.setText(getString(R.string.txt_step_sensor_not_available));
isStepSensorAvailable = false;
}
}
private void initialize() {
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
txtSteps = findViewById(R.id.txtSteps);
txtCheck = findViewById(R.id.txtCheck);
stepCounter = 0;
btnReset = findViewById(R.id.btnReset);
btnReset.setVisibility(View.INVISIBLE);
txtSteps.setVisibility(View.INVISIBLE);
}
/**
* Checking for available Sensors
*/
#Override
protected void onResume()
{
super.onResume();
if(sensorManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR) != null)
{
sensorManager.registerListener(this, stepSensor, sensorManager.SENSOR_DELAY_FASTEST);
txtCheck.setText(txtCheck.getText() + System.getProperty("line.separator") + "listener registered!");
}
}
#Override
protected void onPause()
{
super.onPause();
if(sensorManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR) != null)
{
sensorManager.unregisterListener(this, stepSensor);
}
}
#Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor == stepSensor)
{
txtCheck.setText(txtCheck.getText() + System.getProperty("line.separator") + "Sensorevent was triggered!");
stepCounter = (int) (stepCounter + event.values[0]);
txtSteps.setText(String.valueOf(stepCounter));
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
Thanks in advance for all the help.
Replace
if (event.sensor == stepSensor)
with
if (event.sensor.getType() == Sensor.TYPE_STEP_DETECTOR)
You need to add the following to your AndroidManifest.xml:
<uses-feature
android:name="android.hardware.sensor.stepcounter"
android:required="true"/>
<uses-feature
android:name="android.hardware.sensor.stepdetector"
android:required="true"/>
If you use Android 10 or later, you also need to add the following permission:
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/>
Related
I have to log my Sensor data from my Android Phone to a csv. file so I can use it further , the problem is I tried something with some code(FileWriter to csv) that I found and put it into my code and it does not work, can maybe someone tell me what I do wrong, where my error is. The idea is to just record different sensor data with different EventHandlers like in the Code Example and then write the sensor data to a csv. file together and that csv. file should be on the phone.
I have maybe to mention that I have never before programed in Java or did Android , so please try to answer me as simple as possible, thank you :)
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.CompoundButton;
import android.widget.ProgressBar;
import android.widget.Switch;
import android.widget.TextView;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class MainActivity extends AppCompatActivity {
TextView txt_currentAccel, txt_prevAccel, txt_acceleration, txt_temp;
ProgressBar prog_shakeMeter;
Switch switch1;
//define Sensor Variables
private SensorManager mSensorManager;
private Sensor mAccelerometer;
private SensorManager mSensorManagerNew;
private Sensor mTemp;
private double accelerationCurrentValue;
private double accelerationPreviousValue;
private int SwitchFlag = 0;
final String TAG = "SensorLog";
FileWriter writer;
private SensorEventListener sensorEventListener = new SensorEventListener() {
#Override
public void onSensorChanged(SensorEvent sensorEvent) {
if (sensorEvent.sensor.getType() == Sensor.TYPE_ACCELEROMETER && SwitchFlag == 1) {
float x = sensorEvent.values[0];
float y = sensorEvent.values[1];
float z = sensorEvent.values[2];
accelerationCurrentValue = Math.sqrt((x * x + y * y + z * z));
double changeInAcceleration = Math.abs(accelerationCurrentValue - accelerationPreviousValue);
accelerationPreviousValue = accelerationCurrentValue;
//update text views
txt_currentAccel.setText("Current =" + accelerationCurrentValue);
txt_prevAccel.setText(("Prev = " + accelerationPreviousValue));
txt_acceleration.setText("Acceleration change =" + changeInAcceleration);
prog_shakeMeter.setProgress((int) changeInAcceleration);
try {
writer.write(String.format("ACC; %f; %f; %f; %f; %f; %f\n", sensorEvent.values[0], sensorEvent.values[1], sensorEvent.values[2], 0.f, 0.f, 0.f));
}catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int i) {
}
};
private SensorEventListener sensorEventListenerNew = new SensorEventListener() {
#Override
public void onSensorChanged(SensorEvent sensorEvent) {
float temp = sensorEvent.values[0];
txt_temp.setText("Temp = " + temp);
}
#Override
public void onAccuracyChanged(Sensor sensor, int i) {
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txt_acceleration = findViewById(R.id.txt_accel);
txt_prevAccel = findViewById(R.id.txt_prevAccel);
txt_currentAccel = findViewById(R.id.txt_currentAccel);
txt_temp = findViewById(R.id.txt_temp);
prog_shakeMeter = findViewById(R.id.prog_shakeMeter);
switch1 = findViewById(R.id.switch1);
// Initialize Sensors
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mSensorManagerNew = (SensorManager) getSystemService(SENSOR_SERVICE);
mTemp = mSensorManagerNew.getDefaultSensor(Sensor.TYPE_LIGHT);
switch1.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
if (b == true) {
SwitchFlag = 1;
} else {
SwitchFlag = 0;
}
}
});
}
public void flag() {
if (SwitchFlag == 1) {
Log.d(TAG, "Writing to " + getStorageDir());
try {
writer = new FileWriter(new File(getStorageDir(), "sensors_" + System.currentTimeMillis() + ".csv"));
} catch (
IOException e) {
e.printStackTrace();
}
} else {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
protected void onResume() {
super.onResume();
mSensorManager.registerListener(sensorEventListenerNew, mTemp, SensorManager.SENSOR_DELAY_NORMAL);
mSensorManager.registerListener(sensorEventListener, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
}
protected void onPause() {
super.onPause();
mSensorManager.unregisterListener(sensorEventListener);
mSensorManager.unregisterListener(sensorEventListenerNew);
}
private String getStorageDir() {
return this.getExternalFilesDir(null).getAbsolutePath();
}
}
I have put somehow together a code that records my sensor data from the phone and i want to save them as csv file in some directory (maybe DCIM) in the internal Storage on the phone, but i cannot find something similar, i am also new to Android Studio and java.
On the bottom you can see ,i found that code example with
"getExternalFilesDir(null).getAbsolutePath()" , how can i change that , that my file is saved on the phone in internal storage and tell him exactly where so i can find it later and use it further ?
package com.example.shakedemo;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.CompoundButton;
import android.widget.ProgressBar;
import android.widget.Switch;
import android.widget.TextView;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class MainActivity extends AppCompatActivity {
TextView txt_currentAccel, txt_prevAccel, txt_acceleration, txt_temp;
ProgressBar prog_shakeMeter;
Switch switch1;
//define Sensor Variables
private SensorManager mSensorManager;
private Sensor mAccelerometer;
private SensorManager mSensorManagerNew;
private Sensor mTemp;
private double accelerationCurrentValue;
private double accelerationPreviousValue;
private int SwitchFlag = 0;
final String TAG = "SensorLog";
FileWriter writer;
private SensorEventListener sensorEventListener = new SensorEventListener() {
#Override
public void onSensorChanged(SensorEvent sensorEvent) {
if (sensorEvent.sensor.getType() == Sensor.TYPE_ACCELEROMETER && SwitchFlag == 1) {
float x = sensorEvent.values[0];
float y = sensorEvent.values[1];
float z = sensorEvent.values[2];
accelerationCurrentValue = Math.sqrt((x * x + y * y + z * z));
double changeInAcceleration = Math.abs(accelerationCurrentValue - accelerationPreviousValue);
accelerationPreviousValue = accelerationCurrentValue;
//update text views
txt_currentAccel.setText("Current =" + accelerationCurrentValue);
txt_prevAccel.setText(("Prev = " + accelerationPreviousValue));
txt_acceleration.setText("Acceleration change =" + changeInAcceleration);
prog_shakeMeter.setProgress((int) changeInAcceleration);
try {
writer.write(String.format("ACC; %f; %f; %f; %f; %f; %f\n", sensorEvent.values[0], sensorEvent.values[1], sensorEvent.values[2], 0.f, 0.f, 0.f));
}catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int i) {
}
};
private SensorEventListener sensorEventListenerNew = new SensorEventListener() {
#Override
public void onSensorChanged(SensorEvent sensorEvent) {
float temp = sensorEvent.values[0];
txt_temp.setText("Temp = " + temp);
}
#Override
public void onAccuracyChanged(Sensor sensor, int i) {
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txt_acceleration = findViewById(R.id.txt_accel);
txt_prevAccel = findViewById(R.id.txt_prevAccel);
txt_currentAccel = findViewById(R.id.txt_currentAccel);
txt_temp = findViewById(R.id.txt_temp);
prog_shakeMeter = findViewById(R.id.prog_shakeMeter);
switch1 = findViewById(R.id.switch1);
// Initialize Sensors
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mSensorManagerNew = (SensorManager) getSystemService(SENSOR_SERVICE);
mTemp = mSensorManagerNew.getDefaultSensor(Sensor.TYPE_LIGHT);
switch1.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
if (b == true) {
Log.d(TAG, "Writing to " + getStorageDir());
try {
writer = new FileWriter(new File(getStorageDir(), "sensors_" + System.currentTimeMillis() + ".csv"));
} catch (
IOException e) {
e.printStackTrace();
}
SwitchFlag = 1;
} else {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
SwitchFlag = 0;
}
}
});
}
protected void onResume() {
super.onResume();
mSensorManager.registerListener(sensorEventListenerNew, mTemp, SensorManager.SENSOR_DELAY_NORMAL);
mSensorManager.registerListener(sensorEventListener, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
}
protected void onPause() {
super.onPause();
mSensorManager.unregisterListener(sensorEventListener);
mSensorManager.unregisterListener(sensorEventListenerNew);
}
private String getStorageDir() {
return this.getExternalFilesDir(null).getAbsolutePath();
}
}
Yesterday i ask a simplified question of my problem, but think its too simplified.
What my programm should do, is to hear a keyword and when he hear it, he should listen to what i said. (like if you told to siri or google now, by saying siri or ok google).
I'm using pocketsphinx for the keyword and the google speechrecognizer for the longer parts. It works, but only for one time. The pocketsphinx is in the MainActivity and the google recognizer is in an extra class (Jarvis).
The programm starts with the pocketsphinx listener, when he hear the KEYPHRASE, he starts the google listener by calling jarvis.startListener() (by the next()-method) and there is the problem, when the googlelistener is done, i dont come back from the Jarvis-class to the MainActivity to call the next() method again.
(when the google recognizer is done, the last things he do is in the onResult() in Jarvis-class, but from there i cant call the next()-method from MainActivity-class)
MainActivity
package com.example.superuser.jarvis;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.speech.RecognitionListener;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import edu.cmu.pocketsphinx.Assets;
import edu.cmu.pocketsphinx.Hypothesis;
import edu.cmu.pocketsphinx.SpeechRecognizer;
import edu.cmu.pocketsphinx.SpeechRecognizerSetup;
import static android.widget.Toast.makeText;
import static edu.cmu.pocketsphinx.SpeechRecognizerSetup.defaultSetup;
public class MainActivity extends Activity implements edu.cmu.pocketsphinx.RecognitionListener {
private String LOG_TAG = "Jarvis_hears_anything";
private TextView tv;
private Jarvis jarvis;
private boolean wannahearjarvis = false;
/* Named searches allow to quickly reconfigure the decoder */
private static final String KWS_SEARCH = "wakeup";
/* Keyword we are looking for to activate menu */
private static final String KEYPHRASE = "jarvis";
private edu.cmu.pocketsphinx.SpeechRecognizer recognizer;
//private HashMap<String, Integer> captions;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Button button = (Button) findViewById(R.id.b1);
tv = (TextView) findViewById(R.id.tv1);
//captions = new HashMap<String, Integer>();
//captions.put(KWS_SEARCH, R.string.kws_caption);
jarvis = new Jarvis(getApplicationContext());
new AsyncTask<Void, Void, Exception>() {
#Override
protected Exception doInBackground(Void... params) {
try {
Assets assets = new Assets(MainActivity.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.tv1))
.setText("Failed to init recognizer " + result);
} else {
//switchSearch(KWS_SEARCH);
recognizer.startListening(KWS_SEARCH);
}
}
}.execute();
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "geht", Toast.LENGTH_SHORT).show();
}
});
}
public void next(){
if (wannahearjarvis){
recognizer.startListening(KWS_SEARCH);
wannahearjarvis = false;
}
else{
jarvis.startListening();
wannahearjarvis = true;
}
}
#Override
public void onDestroy() {
super.onDestroy();
recognizer.cancel();
recognizer.shutdown();
}
/**
* In partial result we get quick updates about current hypothesis. In
* keyword spotting mode we can react here, in other modes we need to wait
* for final result in onResult.
*/
#Override
public void onPartialResult(Hypothesis hypothesis) {
if (hypothesis == null)
return;
String text = hypothesis.getHypstr();
if (text.equals(KEYPHRASE)){
tv.append("found");
recognizer.stop();
//switchSearch(KWS_SEARCH);
}
else {
//((TextView) findViewById(R.id.tv1)).append(text+"PR");
//Log.i(LOG_TAG, text+"PR");
}
}
/**
* This callback is called when we stop the recognizer.
*/
#Override
public void onResult(Hypothesis hypothesis) {
//((TextView) findViewById(R.id.tv1)).setText("");
((TextView) findViewById(R.id.tv1)).append("oR");
if (hypothesis != null) {
String text = hypothesis.getHypstr();
makeText(getApplicationContext(), text, Toast.LENGTH_SHORT).show();
}
next();
}
#Override
public void onBeginningOfSpeech() {
}
/**
* We stop recognizer here to get a final result
*/
#Override
public void onEndOfSpeech() {
if (!recognizer.getSearchName().equals(KWS_SEARCH)){
tv.append("fuck");
}
//switchSearch(KWS_SEARCH);
}
/*private void switchSearch(String searchName) {
recognizer.stop();
// If we are not spotting, start listening with timeout (10000 ms or 10 seconds).
if (searchName.equals(KWS_SEARCH))
recognizer.startListening(searchName);
else
recognizer.startListening(searchName, 10000);
//String caption = getResources().getString(captions.get(searchName));
//((TextView) findViewById(R.id.tv1)).setText(caption);
//((TextView) findViewById(R.id.tv1)).append(caption);
}*/
private void setupRecognizer(File assetsDir) throws IOException {
// The recognizer can be configured to perform multiple searches
// of different kind and switch between them
recognizer = defaultSetup()
.setAcousticModel(new File(assetsDir, "en-us-ptm"))
.setDictionary(new File(assetsDir, "cmudict-en-us.dict"))
// To disable logging of raw audio comment out this call (takes a lot of space on the device)
.setRawLogDir(assetsDir)
// Threshold to tune for keyphrase to balance between false alarms and misses
.setKeywordThreshold(1e-20f)
// Use context-independent phonetic search, context-dependent is too slow for mobile
.setBoolean("-allphone_ci", true)
.getRecognizer();
recognizer.addListener(this);
/** In your application you might not need to add all those searches.
* They are added here for demonstration. You can leave just one.
*/
// Create keyword-activation search.
recognizer.addKeyphraseSearch(KWS_SEARCH, KEYPHRASE);
}
#Override
public void onError(Exception error) {
((TextView) findViewById(R.id.tv1)).setText(error.getMessage());
}
#Override
public void onTimeout() {
//switchSearch(KWS_SEARCH);
}
}
Jarvis
package com.example.superuser.jarvis;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.os.Bundle;
import android.speech.RecognitionListener;
import android.speech.RecognizerIntent;
import android.speech.SpeechRecognizer;
import android.widget.Toast;
import java.util.ArrayList;
public class Jarvis implements RecognitionListener{
private AudioManager audiom;
private SpeechRecognizer speech;
private Intent recogIntent;
private Toast m;
private Context c;
private String text;
public Jarvis(Context context){
speech = SpeechRecognizer.createSpeechRecognizer(context);
speech.setRecognitionListener(this);
recogIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
recogIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_PREFERENCE, "de");
//recogIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, context.getPackageName());
m = new Toast(context);
c=context;
}
public void startListening(){
speech.startListening(recogIntent);
}
public void destroy(){
speech.stopListening();
speech.cancel();
speech.destroy();
}
#Override
public void onReadyForSpeech(Bundle params) {
}
#Override
public void onBeginningOfSpeech() {
}
#Override
public void onRmsChanged(float rmsdB) {
}
#Override
public void onBufferReceived(byte[] buffer) {
}
#Override
public void onEndOfSpeech() {
}
#Override
public void onError(int error) {
}
#Override
public void onResults(Bundle results) {
ArrayList<String> matches = results
.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
Toast.makeText(c, matches.get(0), Toast.LENGTH_LONG).show();
speech.cancel();
//tried
//MainActivity m = new MainActivity();
//m.next();
//but got a Nullpointer Exception
}
#Override
public void onPartialResults(Bundle partialResults) {
}
#Override
public void onEvent(int eventType, Bundle params) {
}
}
You can store reference to the main activity in Jarvis object in a field:
class Jarvis {
....
private MainActivity m;
....
public Jarvis(MainActivity m) {
this.m = m;
}
....
public void onResults(Bundle results) {
....
m.next();
}
You can also send intents to the main activity as described here. This might be overkill in your case though.
I've followed the instructions in this tutorial: http://code.tutsplus.com/tutorials/create-a-live-wallpaper-on-android-using-an-animated-gif--cms-23088
But I have had a few errors and am unable to run my project.
This is all my code:
My manifest:
<service
android:name=".GIFWallpaperService"
android:enabled="true"
android:label="Raindrops In Paris"
android:permission="android.permission.BIND_WALLPAPER" >
<intent-filter>
<action android:name="android.service.wallpaper.WallpaperService"/>
</intent-filter>
<meta-data
android:name="android.service.wallpaper"
android:resource="#xml/wallpaper" >
</meta-data>
</service>
<uses-feature
android:name="android.software.live_wallpaper"
android:required="true" >
</uses-feature>
My Java class:
package com.gacafw.gina.raindropsinparis;
import android.graphics.Canvas;
import android.graphics.Movie;
import android.os.Handler;
import android.service.wallpaper.WallpaperService;
import android.util.Log;
import android.view.SurfaceHolder;
import java.io.IOException;
public class GIFWallpaperService extends WallpaperService {
#Override
public WallpaperService.Engine onCreateEngine() {
try {
Movie movie = Movie.decodeStream(
getResources().getAssets().open("rainDropAna.gif"));
return new GIFWallpaperEngine(movie);
}catch(IOException e){
Log.d("GIF", "Could not load asset");
return null;
}
}
private Runnable drawGIF = new Runnable() {
public void run() {
draw();
}
};
private void draw() {
if (visible) {
Canvas canvas = holder.lockCanvas();
canvas.save();
// Adjust size and position so that
// the image looks good on your screen
canvas.scale(3f, 3f);
movie.draw(canvas, -100, 0);
canvas.restore();
holder.unlockCanvasAndPost(canvas);
movie.setTime((int) (System.currentTimeMillis() % movie.duration()));
handler.removeCallbacks(drawGIF);
handler.postDelayed(drawGIF, frameDuration);
}
}
#Override
public void onVisibilityChanged(boolean visible) {
this.visible = visible;
if (visible) {
handler.post(drawGIF);
} else {
handler.removeCallbacks(drawGIF);
}
}
private class GIFWallpaperEngine extends WallpaperService.Engine {
private final int frameDuration = 20;
private SurfaceHolder holder;
private Movie movie;
private boolean visible;
private Handler handler;
public GIFWallpaperEngine(Movie movie) {
this.movie = movie;
handler = new Handler();
}
#Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
this.holder = surfaceHolder;
}
#Override
public void onDestroy() {
super.onDestroy();
handler.removeCallbacks(drawGIF);
}
}
}
My wallpaper.xml
<?xml version="1.0" encoding="UTF-8"?>
<wallpaper
xmlns:android="http://schemas.android.com/apk/res/android"
android:label="Raindrops In Paris"
android:thumbnail="#drawable/ic_launcher">
</wallpaper>
My errors currently:
The variables visible, holder, movie, handler in the draw() and onVisibilityChanged() are giving the error Cannot Resolve Symbol. I assume this is because they are out of scope in these methods?
I think I interpreted the instructions wrong but I can't figure out where I went wrong.
The tut contains an error - where it says "Add the following code to the GIFWallpaperService class:" it should say add it to the GIFWallpaperEngine class.
I had the same problem.I created an An Activity and passed an intent to run the wallpaper.here is your answer
public class SetWallpaperActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
Intent intent = new Intent(
WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);
intent.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT,
new ComponentName(this, GIFWallpaperService.class));
startActivity(intent);
}
}
My problem is I've created an immersion activity with several cards in it. When I try and swipe between the cards, nothing happens. I can swipe down to end the activity, but I can't swipe between cards. The funny thing is if I let the glass go to sleep and then wake it up again, I can then swipe between cards. Because of this oddity, I'm pretty sure I'm missing one line of code that gives the cards focus or something, but I don't know what it is.
I've found a workaround using a gesture detector, but it doesn't look like normal swiping, so I'd like to avoid that. My code is below:
package com.akqa.glass.recipie;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.TextView;
import com.google.android.glass.media.Sounds;
import com.google.android.glass.view.WindowUtils;
import com.google.android.glass.widget.CardBuilder;
import com.google.android.glass.widget.CardScrollAdapter;
import com.google.android.glass.widget.CardScrollView;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList;
import java.util.List;
/**
* Created by torti_000 on 11/29/2014.
*/
public class PairingsActivity extends Activity {
private CardAdapter mAdapter;
private CardScrollView mCardScroller;
private int mTapPosition;
private final Handler handler = new Handler();
private boolean mVoiceMenuEnabled = true;
private String ingredientUrl = null;
private static final String TAG = "Ingredients";
private static final String URL_BASE = "http://www.ingredientpairings.com/?i=";
private ArrayList<String> iList;
//Number of ingredients to display per card.
private static final int ITEMS_PER_CARD = 4;
private int numCards;
String object = null;
Context context;
private View mView;
#Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
//Loading
mView = buildView();
mCardScroller = new CardScrollView(this);
mCardScroller.setAdapter(new CardScrollAdapter() {
#Override
public int getCount() {
return 1;
}
#Override
public Object getItem(int position) {
return mView;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
return mView;
}
#Override
public int getPosition(Object item) {
if (mView.equals(item)) {
return 0;
}
return AdapterView.INVALID_POSITION;
}
});
setContentView(mCardScroller);
Log.d(TAG, "View has been set");
mCardScroller.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// Plays sound.
AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
am.playSoundEffect(Sounds.TAP);
}
});
//Recipes
iList = new ArrayList<String>();
context = this;
Intent pairings = getIntent();
object = pairings.getStringExtra("Object");
Log.i(TAG, "Pairings thinks object is: " + object);
new GetIngredients().execute(object);
}
/**
* Create Loding Page
*/
private View buildView() {
Log.d(TAG, "Creating Loading Card");
CardBuilder card = new CardBuilder(this, CardBuilder.Layout.TEXT);
card.setText("Loading");
return card.getView();
}
/**
* Creates list of cards that showcase different type of {#link com.google.android.glass.widget.CardBuilder} API.
*/
private List<CardBuilder> createCards(Context context) {
ArrayList<CardBuilder> cards = new ArrayList<CardBuilder>();
Log.i(TAG, "Creating Cards");
/*
* One ingredient per card...
*/
for(int i = 0; i < iList.size(); i++){
cards.add(new CardBuilder(context, CardBuilder.Layout.TEXT)
.setText(iList.get(i)));
Log.d(TAG, "Ingredient is: " + iList.get(i));
}
Log.d(TAG, "Done adding pairings?");
return cards;
}
#Override
protected void onResume() {
super.onResume();
mCardScroller.activate();
}
#Override
protected void onPause() {
mCardScroller.deactivate();
super.onPause();
}
public class GetIngredients extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... strings) {
StringBuffer buffer = new StringBuffer();
try {
ingredientUrl = object.replaceAll(" ", "+");
Log.d(TAG, ingredientUrl);
// strings[0].replaceAll(" ", "+");
Log.d(TAG, "Finding matches for " + object);
Document doc = Jsoup.connect(URL_BASE + ingredientUrl).get();
Log.d(TAG, "Matches found for " + object);
Elements ingredients = doc.select("div.main p b");
// Log.d(TAG, "Ingredients are: " + ingredients.toString());
for (Element ingredient : ingredients) {
String data = ingredient.text();
iList.add(data);
buffer.append("Data [" + data + "] \r\n");
Log.d(TAG, "Ingredient is: " + data);
}
}
catch(Throwable t) {
t.printStackTrace();
}
return buffer.toString();
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
// Compute the number of cards needed to display the items with 4 per card (rounding up to
// capture the remainder).
numCards = (int) Math.ceil((double) iList.size() / ITEMS_PER_CARD);
startCards();
}
}
private void startCards(){
mAdapter = new CardAdapter(createCards(this));
// mCardScroller = new CardScrollView(this);
mCardScroller.setAdapter(mAdapter);
setContentView(mCardScroller);
}
}
In your onCreate(), add this line before the setContentView() like this:
mCardScroller.activate(); //add this line
setContentView(mCardScroller);
You had this line in your onResume() and that's why it is behaving as is.
I had a problem where I was switching the content view between a CardScrollView and a SurfaceView. After I made sure that onPause() and onResume() were both called in the logically correct places, the scroller was fine.
It seems like if the CardScrollView has lost focus then the scroller loses functionality and calling .activate() only works if .deactivate() has been called beforehand, hence why both onPause() and onResume() need to both be called in the logically correct places as .deactivate() is called within onPause() and .activate() is called within onResume(). I tried just calling .deactivate() and .activate() on their own instead of onPause() and onResume() and the behaviour was the same in both instances, supporting what I have written here.
So, in short, if switching between views with setContentView(), be sure to call onPause() before the switch and onResume() after the switch otherwise the scroller will stop responding.