You are on page 1of 38

Internal Services

https://developer.android.com/docs/ (Sensors)

1
Internal Services

 Communication: Email, SMS and telephony


 Audio and video: Record and playback
 Sensors: Accelerometer, light, magnetic, ambient
temperature

2
Sending Email: Java
public void sendScoresViaEmail() {
Intent emailIntent =
new Intent(android.content.Intent.ACTION_SEND);
emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT,
"Look at my AWESOME TicTacToe Score!");
// Can also fill To: using putExtra(..., EXTRA_EMAIL)
emailIntent.setType("plain/text");
emailIntent.putExtra(android.content.Intent.EXTRA_TEXT,
firstPlayerName + " score is " + scorePlayerOne +
" and " + secondPlayerName + " score is " +
scorePlayerTwo);
startActivity(emailIntent);
}

How to send email programmatically: http://www.oodlestechnologies.com/blogs/


Send-Mail-in-Android-without-Using-Intent (or 3
search online)
Sending Email: Kotlin
fun sendScoresViaEmail() {
val emailIntent = Intent(Intent.ACTION_SEND)
emailIntent.putExtra(Intent.EXTRA_SUBJECT,
"Look at my AWESOME TicTacToe Score!")
emailIntent.type = "plain/text"
emailIntent.putExtra(Intent.EXTRA_TEXT,
mFirstPlayerName + " score is " + mScorePlayerOne + " and " +
mSecondPlayerName + " score is " + mScorePlayerTwo)
startActivity(emailIntent)
}

4
SMS: Java
public void sendScoresViaSMS() {
Intent SMSIntent = new Intent(Intent.ACTION_VIEW);
SMSIntent.putExtra("sms_body",
"Look at my AWESOME TicTacToe Score!" +
firstPlayerName + " score is " + scorePlayerOne +
" and " + secondPlayerName + " score is " +
scorePlayerTwo);
SMSIntent.setType("vnd.android-dir/mms-sms");
startActivity(SMSIntent);
}

Can also use http://developer.android.com/reference/android/telephony/SmsManager.html


. 5

You need <uses-permission android:name=”android.permission.SEND_SMS”/>


SMS: Kotlin
fun sendScoresViaSMS() {
val SMSIntent = Intent(Intent.ACTION_VIEW)
SMSIntent.putExtra("sms_body",
"Look at my AWESOME TicTacToe Score!" + mFirstPlayerName +
" score is " + mScorePlayerOne + " and " +
mSecondPlayerName + " score is " + mScorePlayerTwo)
SMSIntent.type = "vnd.android-dir/mms-sms"
startActivity(SMSIntent)
}

6
Telephony: Java
public void callTicTacToeHelp() {
Intent phoneIntent = new Intent(Intent.ACTION_DIAL);
String phoneNumber = "842-822-4357"; // TIC TAC HELP
String uri = "tel:" + phoneNumber.trim();
phoneIntent.setData(Uri.parse(uri));
startActivity(phoneIntent);
}

Needs:
<uses-permission
android:name="android.permission.CALL_PHONE"/>

7
Telephony: Kotlin

fun callTicTacToeHelp() {
val phoneIntent = Intent(Intent.ACTION_DIAL)
val phoneNumber = "842-822-4357" // TIC TAC HELP
val uri = "tel:" + phoneNumber.trim { it <= ' ' }
phoneIntent.data = Uri.parse(uri)
startActivity(phoneIntent)
}

8
Playing Audio Example: Setup
1. <?xml version="1.0" encoding="utf-8"?>
<LinearLayout ... >
<Button ... android:text="Start Audio"/>
<Button ... android:text="Stop Audio”/>
<Button ... android:text="Record Audio"/>
<Button ... android:text="Exit" />
</LinearLayout>

2.

View device file system in Android Studio. Transfer


files via your computer’s OS (ensure drivers are
installed first).

Media file is sampleAudio.mp3 in external storage


“music directory” (varies among devices).

Next slides show


9
AudioFragment code (Java, Kotlin).
// AudioFragment.java
private String mAudioFilePath = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_MUSIC).getPath() + File.separator + "sample_audio.mp3";
private Intent mRecordAudioIntent = new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION)
private Uri mAudioFileUri; // . . .
@Override
public void onClick(View view) {
Activity activity = getActivity();
if (activity != null) {
switch (view.getId()) {
case R.id.buttonAudioStart:
if (!mStarted) {
1
Intent musicIntent = new Intent(activity, MediaPlaybackService.class);
musicIntent.putExtra("URIString", mAudioFileUri.toString());
activity.startService(musicIntent); mStarted = true; } break;
case R.id.buttonAudioStop:
activity.stopService(new Intent(activity, MediaPlaybackService.class)); 2
mStarted = false; break;
case R.id.buttonAudioRecord:
startActivityForResult(mRecordAudioIntent, AUDIO_CAPTURED); break;
}
}
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK && requestCode == AUDIO_CAPTURED) { 3
mAudioFileUri = data.getData(); } } 10
// AudioFragment.kt
private val mAudioFilePath = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_MUSIC).path + File.separator + "sample_audio.mp3"
private lateinit var mAudioFileUri: Uri
private val mRecordAudioIntent = Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION)
override fun onClick(view: View) {
when (view.id) {
R.id.buttonAudioStart -> if (!mStarted) {
val musicIntent = Intent(activity?.applicationContext, 1
MediaPlaybackService::class.java)
musicIntent.putExtra("URIString", mAudioFileUri.toString())
activity?.startService(musicIntent)
mStarted = true }
R.id.buttonAudioStop -> {
activity?.stopService(Intent(activity?.applicationContext,
2
MediaPlaybackService::class.java))
mStarted = false }
R.id.buttonAudioRecord -> startActivityForResult(mRecordAudioIntent,AUDIO_CAPTURED)
}
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {


if (resultCode == RESULT_OK && requestCode == AUDIO_CAPTURED) {
3
if (data != null) {
mAudioFileUri = data.data }
} 11
}
Media Player States

12
Source: https://developer.android.com/reference/android/media/MediaPlayer.html
Playing Audio: Service: Java
<service android:enabled="true” android:name=".MediaPlaybackService”/>
// MediaPlayerService.java
public class MediaPlaybackService extends Service {
MediaPlayer player;

@Override
public IBinder onBind(Intent intent) { return null;}

@Override
public void onCreate() {
player = MediaPlayer.create(this, R.raw.sample_audio); player.setLooping(true); }

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
Bundle extras = intent.getExtras();
if (extras != null) {
String audioFileURIString = extras.getString("URIString");
Uri audioFileURI = Uri.parse(audioFileURIString);
try {
player.reset(); player.setDataSource(this.getApplicationContext(), audioFileURI);
player.prepare(); player.start();
} catch (Exception e) { e.printStackTrace(); }
}
return START_STICKY; }

@Override
13
public void onDestroy() { player.stop(); }
}
Playing Audio: Service: Kotlin
<service android:enabled="true” android:name=".MediaPlaybackService”/>
// MediaPlayerService.kt
class MediaPlaybackService : Service() {
internal lateinit var player: MediaPlayer
override fun onBind(intent: Intent): IBinder? { return null}

override fun onCreate() {


player = MediaPlayer.create(this, R.raw.sample_audio)
player.apply { isLooping = true } }

override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {


super.onStartCommand(intent, flags, startId)
val extras = intent.extras
if (extras != null) {
val audioFileURIString = extras.getString("URIString")
val audioFileURI = Uri.parse(audioFileURIString)
try {
player.reset()
player.setDataSource(this.applicationContext, audioFileURI)
player.prepare()
player.start()
} catch (e: Exception) { /* Error handling */ }

return Service.START_STICKY
}

override fun onDestroy() { player.stop() } 14


}
Handling Video Using VideoView
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout ... >
<VideoView android:id="@+id/videoView"
android:layout_height="175dip"
android:layout_width="match_parent"
android:layout_gravity="center" />
<Button ... android:text="Start Video"/>
<Button ... android:text="Stop Video”/>
<Button ... android:text="Record Video"/>
<Button ... android:text="Exit" />
</LinearLayout>

15
// VideoFragment.java Handling Video:
Java (1)
public class VideoFragment extends Fragment
implements View.OnClickListener {
private Button mButtonStart, mButtonStop, mButtonRecord;
private VideoView mVideoView = null;
private Uri mVideoFileUri = null;
private Intent mRecordVideoIntent =
new Intent(android.provider.MediaStore.ACTION_VIDEO_CAPTURE);

@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Activity activity = getActivity();
View v = inflater.inflate(R.layout.fragment_video, container, false);
mVideoView = v.findViewById(R.id.videoView);
// Get references to Buttons and for each Button, setOnClickListener(this);
String path =
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES).getPath()
+ File.separator + "sample_video.mp4";
File videoFile = new File(path);
if (videoFile.exists()) { mVideoFileUri = Uri.fromFile(videoFile); }
else { // Video file doesn't exist, so load sample video from resources.
if (activity != null) {
String videoResourceName = "android.resource://" + activity.getPackageName() +
File.separator + R.raw.sample_video;
mVideoFileUri = Uri.parse(videoResourceName); } }
// Guard against no video recorder app (disable the "record" button).
return v; 16
}
}
Handling Video: Java (2)
// VideoFragment.java (continued)
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.buttonVideoStart:
// Load and start the movie
mVideoView.setVideoURI(mVideoFileUri);
mVideoView.start();
break;
case R.id.buttonVideoRecord:
startActivityForResult(mRecordVideoIntent, VIDEO_CAPTURED);
break;
case R.id.buttonVideoStop:
mVideoView.stopPlayback();
break;
case R.id.buttonVideoExit:
Activity activity = getActivity();
if (activity != null) { activity.finish(); }
break;
}
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK && requestCode == VIDEO_CAPTURED) {
mVideoFileUri = data.getData();
}
} 17
}
// AudioFragment.kt
class VideoFragment : Fragment(),
View.OnClickListener {
private lateinit var mButtonStart: Button
Handling Video:
private lateinit var mButtonStop: Button
private lateinit var mButtonRecord: Button
private lateinit var mVideoView: VideoView
Kotlin (1)
private var mVideoFileUri: Uri? = null
private val mRecordVideoIntent = Intent(android.provider.MediaStore.ACTION_VIDEO_CAPTURE)

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,


savedInstanceState: Bundle?): View? {
val v = inflater.inflate(R.layout.fragment_audio, container, false)
mVideoView = v.findViewById(R.id.videoView)
// Get references to Buttons and for each Button, setOnClickListener(this);
val path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES)
.path + File.separator + "sample_video.mp4"
val videoFile = File(path)
if (videoFile.exists()) { mVideoFileUri = Uri.fromFile(videoFile) }
else {
// Video file doesn't exist, so load sample video from resources.
val videoResourceName = "android.resource://" + activity?.packageName +
File.separator + R.raw.sample_video
mVideoFileUri = Uri.parse(videoResourceName) }
// Guard against no video recorder app (disable the "record" button).
return v 18
}
Handling Video: Kotlin (2)
override fun onClick(view: View) {
when (view.id) {
R.id.buttonVideoStart -> {
// Load and start the movie
mVideoView.setVideoURI(mVideoFileUri)
mVideoView.start()
}
R.id.buttonVideoRecord -> startActivityForResult(mRecordVideoIntent, VIDEO_CAPTURED)
R.id.buttonVideoStop -> mVideoView.stopPlayback()
R.id.buttonVideoExit -> activity?.finish()
}
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {


if (resultCode == RESULT_OK && requestCode == VIDEO_CAPTURED) {
if (data != null) {
mVideoFileUri = data.data
}
}
} 19
Handling Images: ImageView
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout ... >
<ImageView android:id="@+id/imageView"
android:layout_height="175dip"
android:layout_width="match_parent"
android:layout_gravity="center" />
<Button ... android:text="Show Image"/>
<Button ... android:text="Take Picture"/>
<Button ... android:text="Exit" />
</LinearLayout>

20
Handling Images: Java (1)
// ImageFragment.java
public class ImagesFragment extends Fragment implements View.OnClickListener {
private ImageView imageView = null;
private static Uri imageFileURI;
private String imageFilePath = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES).getPath() + File.separator + "other_image.png";
private Bitmap imageBitmap = null;
private Intent mCaptureImageIntent = new Intent(
android.provider.MediaStore.ACTION_IMAGE_CAPTURE);

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_images, container, false);

imageView = (ImageView) v.findViewById(R.id.imageView);

Button buttonShow = v.findViewById(R.id.buttonImageShow);


Button buttonCapture = v.findViewById(R.id.buttonImageCapture);
// Set up onClickListener(this) for the buttons

return v; 21
}
Handling Images: Java (2)
// ImageFragment.java (continued)
@Override
public void onClick(View view) {
switch(view.getId()) {
case R.id.buttonImageShow:
File imageFile = new File(imageFilePath);
if (imageFile.exists()) {
imageBitmap = BitmapFactory.decodeFile(imageFilePath);
imageView.setImageBitmap(imageBitmap);
} else {
// File doesn't exist, so load a sample SVG image.
imageView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
imageView.setImageResource(R.drawable.ic_scoreboard); }
break;
case R.id.buttonImageCapture:
startActivityForResult(mCaptureImageIntent, IMAGE_CAPTURED);
break;
case R.id.buttonImageExit:
// Finish Activity; call break
} 22
}
Handling Images: Java (3)

// ImageFragment.java (continued)
public void onActivityResult(int requestCode, int resultCode, Intent
cameraIntent) {
if (resultCode == RESULT_OK && requestCode == IMAGE_CAPTURED) {
Bundle extras = cameraIntent.getExtras();
if (extras != null) {
imageBitmap = (Bitmap) extras.get("data");
imageView.setImageBitmap(imageBitmap);
}
}
}

Memory management is critical for Bitmaps! Consider using LRU


cache, library like Glide (https://github.com/bumptech/glide) to
handle them. See https://developer.android.com/topic/
performance/graphics/index.html for more info. (See also:
https://issuetracker.google.com/issues/36917456
23
)
Handling Images: Kotlin (1)
// ImagesFragment.kt
class ImagesFragment : Fragment(), View.OnClickListener {
private lateinit var imageView: ImageView
private val imageFilePath = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES).path + File.separator + "other_image.png"
private lateinit var imageBitmap: Bitmap
private lateinit var imageFileURI: Uri

private val mCaptureImageIntent = Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE)

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,


savedInstanceState: Bundle?): View? {
val v = inflater.inflate(R.layout.fragment_images, container, false)

imageView = v.findViewById(R.id.imageView)
val buttonShow = v.findViewById(R.id.buttonImageShow)
val buttonCapture = v.findViewById(R.id.buttonImageCapture)
// Set onClickListener(this) for each Button

return v
} /* . . . */ 24
Handling Images: Kotlin (2)
// ImagesFragment.kt (continued)
override fun onClick(view: View) {
when (view.id) {
R.id.buttonImageShow -> {
val imageFile = File(imageFilePath)
if (imageFile.exists()) {
imageBitmap = BitmapFactory.decodeFile(imageFilePath)
imageView.setImageBitmap(imageBitmap)
} else {
// File doesn't exist, so load a sample SVG image.
// Disable hardware acceleration for SVGs
imageView.setLayerType(View.LAYER_TYPE_SOFTWARE, null)
imageView.setImageResource(R.drawable.ic_scoreboard)
}
}
R.id.buttonImageCapture -> startActivityForResult(mCaptureImageIntent,
IMAGE_CAPTURED)
}
}

25
Handling Images: Kotlin (3)
// ImagesFragment.kt (continued)
override fun onActivityResult(requestCode: Int, resultCode: Int,
cameraIntent: Intent?) {
if (resultCode == RESULT_OK && requestCode == IMAGE_CAPTURED) {
val extras = cameraIntent?.extras
if (extras != null) {
imageBitmap = extras.get("data") as Bitmap
imageView.setImageBitmap(imageBitmap)
}
}
}

26
Sensors
 Uses:
 Provide contextual and environmental data to app
 Tailor app to environment, how people are using devices
 Example Tic-Tac-Toe files:
 SensorsFragment class
 fragment_sensors.xml, list_item_sensor.xml
 Issues:
 Noisy sensor data on real-world devices
 Best tested on real devices. To simulate sensors on the emulator see:
https://github.com/openintents/sensorsimulator
 Inexpensive devices: Moto E (4th gen.), Moto G (5th gen.). See:
http://thewirecutter.com/reviews/best-budget-android-phone, Amazon, eBay

Type Examples
Motion Accelerometer, gyroscope
Environmental Light, temperature, humidity, barometric pressure
Miscellaneous Camera, microphone,
27 fingerprint, infrared
Displaying Sensors
 Display all device sensors (and their Views
info) in a RecyclerView
 RecyclerView: displays (possibly
large) dynamic list/grid of “items”
with limited memory footprint
 More info:
https://developer.android.com/
guide/topics/ui/layout/recyclerview.
html

28
RecyclerView Workflow

Source: Figs. 8.6–8.7, Bill Phillips, Chris


29 Stewart, and Kristin Marsicano,
Android Programming: The Big Nerd Ranch Guide, 3rd ed., 2017.
Listing Available Sensors: Java
private RecyclerView mSensorRecyclerView;
private SensorAdapter mSensorAdapter;
private SensorManager mSensorManager;
private List<Sensor> mSensorList;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_sensor_list, container, false);
Activity activity = getActivity();
RecyclerView sensorRecyclerView = v.findViewById(R.id.sensor_recycler_view);
if (activity != null) {
sensorRecyclerView.setLayoutManager(new LinearLayoutManager(activity));
mSensorManager = (SensorManager) activity.getSystemService(SENSOR_SERVICE);
if (mSensorManager != null) {
mSensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL);
SensorAdapter adapter = new SensorAdapter(mSensorList);
sensorRecyclerView.setAdapter(adapter);
sensorRecyclerView.setItemAnimator(new DefaultItemAnimator()); } }
return v; 30
}
Listing Available Sensors: Kotlin
private lateinit var mSensorRecyclerView: RecyclerView
private lateinit var mAdapter: SensorAdapter
private lateinit var mSensorManager: SensorManager
private lateinit var mSensorList: List<Sensor>
private var lastSensorValues = Hashtable<String, FloatArray>()

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,


savedInstanceState: Bundle?): View? {
val v = inflater.inflate(R.layout.fragment_sensor_list, container, false)
mSensorRecyclerView = v.findViewById(R.id.sensor_recycler_view)
mSensorRecyclerView.layoutManager = LinearLayoutManager(activity)
mSensorManager = activity?.getSystemService(SENSOR_SERVICE) as SensorManager
mSensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL)
mAdapter = SensorAdapter(mSensorList)
mSensorRecyclerView.adapter = mAdapter
mSensorRecyclerView.itemAnimator = DefaultItemAnimator()
return v
}
31
Sensor Holder
Java Kotlin
private class SensorHolder extends private inner class SensorHolder(
RecyclerView.ViewHolder { inflater: LayoutInflater, parent: ViewGroup) :
private Sensor mSensor; RecyclerView.ViewHolder(
private String mDescriptionStr; inflater.inflate(R.layout.list_item_sensor,
parent, false)) {
private TextView mSensorInfoTextView;
private lateinit var mSensor: Sensor
private lateinit var mDescriptionStr: String
public SensorHolder(LayoutInflater inflater,
private val mSensorInfoTextView: TextView
ViewGroup parent) {
super(inflater.inflate( init { mSensorInfoTextView =
R.layout.list_item_sensor, parent, false)); itemView.findViewById(R.id.sensor_data)
mSensorInfoTextView = }
itemView.findViewById(R.id.sensor_data);
} fun bind(sensor: Sensor) {
mSensor = sensor
public void bind(Sensor sensor) { mDescriptionStr = getSensorDescription(
mSensor = sensor; sensor)
mSensorInfoTextView.text = mDescriptionStr
mDescriptionStr = getSensorDescription(sensor);
}
mSensorInfoTextView.setText(mDescriptionStr);
}
}
} 32
Sensor Adapter
Java Kotlin
private class SensorAdapter extends private inner class SensorAdapter(
RecyclerView.Adapter<SensorHolder> { private val mSensorList: List<Sensor>) :
private List<Sensor> mSensorList; RecyclerView.Adapter<SensorHolder>() {
public SensorAdapter(List<Sensor> sensorList) {
mSensorList = sensorList; }
override fun onCreateViewHolder(
parent: ViewGroup, viewType: Int): SensorHolder {
@Override
val inflater = LayoutInflater.from(activity)
public SensorHolder onCreateViewHolder(
return SensorHolder(inflater, parent)
ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from( }
getActivity());
return new SensorHolder(inflater, parent); override fun onBindViewHolder(holder: SensorHolder,
} position: Int) {
val sensor = this@SensorsFragment.
@Override mSensorList[position]
public void onBindViewHolder(SensorHolder holder, holder.bind(sensor)
int position) {
}
Sensor sensor = SensorsFragment.this.mSensorList
.get(position);
override fun getItemCount(): Int {
String sensorDescription = getSensorDescription(
sensor); holder.bind(sensor); return mSensorList.size }
} }
@Override
public int getItemCount() {
return SensorList.size(); } 33

}
Registering Sensor Updates

@Override override fun onResume() {


public void onResume() { super.onResume() // . . .
super.onResume(); // . . . // Start listening to sensor updates
Java
// Start listening to sensor updates Kotlin
for (sensor in mSensorList) {
for (Sensor sensor : mSensorList) { mSensorManager.registerListener(
mSensorManager.registerListener( this, sensor,
this, sensor, SensorManager.SENSOR_DELAY_NORMAL)
SensorManager.SENSOR_DELAY_NORMAL); }
} }
} // . . .
// . . . override fun onPause() {
@Override super.onPause()
public void onPause() { // Stop updates when paused
super.onPause(); mSensorManager.unregisterListener(this)
// Stop updates when paused }
mSensorManager.unregisterListener(this);
} 34
Receiving Sensor Updates
Kotlin
@Override override fun onSensorChanged(
public void onSensorChanged( sensorEvent: SensorEvent) {
SensorEvent sensorEvent) { val sensorEventString =
Java
String sensorEventString = sensorEventToString(sensorEvent)
sensorEventToString(sensorEvent);
// . . . // . . .
Log.d(TAG, "--- EVENT Raw Values ---\n" +
Log.d(TAG, "--- EVENT Raw Values ---\n” +
sensorName + "\n" + "Distance Last = >” + sensorName + "\nDistance Last= >" +
distanceOfLastValue + "<\n" + distanceOfLastValue + "<\n" +
"Distance This = >" + "Distance This= >" +
distanceOfThisValue + "<\n" + distanceOfThisValue + "<\n" +
"Change = >" + change + "<\n" + "Change = >" + change + "<\n" +
"Percent = >" + percentageChange + "Percent = >" + percentageChange +
"%\n" + "Last value = " + "%\n" + "Last value = " +
lastValueString + "<\n" + lastValueString + "<\n" +
sensorEventString);
sensorEventString)
}
}
See complete method for how to
35 filter out noise.
Extracting Sensor Parameters

public String getSensorDescription(


Sensor sensor) {
return "Sensor: " + sensor.getName() +
Java
"; Ver :" + sensor.getVersion() + Kotlin
"; Range: " + sensor.getMaximumRange() +
"; Power: " + sensor.getPower() + fun getSensorDescription(
"; Res: " + sensor.getResolution(); sensor: Sensor): String {
} return "Sensor: " + sensor.name +
"; Ver :" + sensor.version +
"; Range: " + sensor.maximumRange
+
"; Power: " + sensor.power +
"; Res: " + sensor.resolution
}

36
References
 Chapter 8 from Android Programming: The Big Nerd Ranch Guide, 3rd ed. (RecyclerView)
 Services: http://developer.android.com/guide/topics/fundamentals/services.html
 SMS: http://developer.android.com/reference/android/telephony/SmsManager.html
 SIP (internet telephony): http://developer.android.com/reference/android/net/sip/package-
summary.html
 MediaPlayer: http://developer.android.com/reference/android/media/MediaPlayer.html
 MediaRecorder: http://developer.android.com/reference/android/media/MediaRecorder.html
 MediaStore class (extract media metadata):
http://developer.android.com/reference/android/provider/MediaStore.html
 Camera: http://developer.android.com/reference/android/hardware/Camera.html
 BitmapFactory: http://developer.android.com/reference/android/graphics/BitmapFactory.html
 Bitmap: http://developer.android.com/reference/android/graphics/Bitmap.html
 Sensor: http://developer.android.com/reference/android/hardware/Sensor.html
 SensorEvent:
http://developer.android.com/reference/android/hardware/SensorEventListener.html
37
Thank You

Questions and comments?

38

You might also like