internal services -...

Post on 18-Aug-2020

4 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Internal Services

CSE 5236: Mobile Application DevelopmentInstructor: Adam C. Champion, Ph.D.Course Coordinator: Dr. Rajiv RamnathReading: Big Nerd Ranch Guide, Chap. 15, 16 (Intents, camera); 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);}

3

How to send email programmatically: http://www.oodlestechnologies.com/blogs/Send-Mail-in-Android-without-Using-Intent (or search online)

Sending Email: Kotlinfun 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);

}

5

Can also use http://developer.android.com/reference/android/telephony/SmsManager.html .You need <uses-permission android:name=”android.permission.SEND_SMS”/>

SMS: Kotlinfun 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: Javapublic 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: Kotlinfun callTicTacToeHelp() {val phoneIntent = Intent(Intent.ACTION_DIAL)val phoneNumber = "842-822-4357" // TIC TAC HELPval uri = "tel:" + phoneNumber.trim { it <= ' ' }phoneIntent.data = Uri.parse(uri)startActivity(phoneIntent)

}

8

Playing Audio Example: Setup

9

<?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>

1.

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 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; // . . .@Overridepublic void onClick(View view) {

Activity activity = getActivity();if (activity != null) {

switch (view.getId()) {case R.id.buttonAudioStart:

if (!mStarted) {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));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) {mAudioFileUri = data.getData(); } }

10

1

2

3

// AudioFragment.kt

private val mAudioFilePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).path + File.separator + "sample_audio.mp3"

private lateinit var mAudioFileUri: Uriprivate 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,

MediaPlaybackService::class.java)musicIntent.putExtra("URIString", mAudioFileUri.toString())activity?.startService(musicIntent)mStarted = true }

R.id.buttonAudioStop -> {activity?.stopService(Intent(activity?.applicationContext,

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) {

if (data != null) {mAudioFileUri = data.data }

}} 11

1

2

3

Media Player States

12Source: 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;

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

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

@Overridepublic 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; }

@Overridepublic void onDestroy() { player.stop(); }

}13

Playing Audio: Service: Kotlin<service android:enabled="true” android:name=".MediaPlaybackService”/>

// MediaPlayerService.ktclass MediaPlaybackService : Service() {internal lateinit var player: MediaPlayeroverride 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.extrasif (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.javapublic 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);

@Overridepublic 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;

}}

Handling Video: Java (1)

16

Handling Video: Java (2)

17

// VideoFragment.java (continued)@Overridepublic void onClick(View view) {

switch (view.getId()) {case R.id.buttonVideoStart:

// Load and start the moviemVideoView.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();

}}

}

// AudioFragment.kt

class VideoFragment : Fragment(), View.OnClickListener {private lateinit var mButtonStart: Buttonprivate lateinit var mButtonStop: Buttonprivate lateinit var mButtonRecord: Buttonprivate lateinit var mVideoView: VideoViewprivate var mVideoFileUri: Uri? = nullprivate 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_videomVideoFileUri = Uri.parse(videoResourceName) }// Guard against no video recorder app (disable the "record" button).

return v}

Handling Video: Kotlin (1)

18

Handling Video: Kotlin (2)override fun onClick(view: View) {

when (view.id) {R.id.buttonVideoStart -> {

// Load and start the moviemVideoView.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);

@Overridepublic 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)

@Overridepublic 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);

}}

}

23

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 )

Handling Images: Kotlin (1)// ImagesFragment.kt

class ImagesFragment : Fragment(), View.OnClickListener {private lateinit var imageView: ImageViewprivate val imageFilePath = Environment.getExternalStoragePublicDirectory(

Environment.DIRECTORY_PICTURES).path + File.separator + "other_image.png"private lateinit var imageBitmap: Bitmapprivate 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 SVGsimageView.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?.extrasif (extras != null) {

imageBitmap = extras.get("data") as BitmapimageView.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

27

Type ExamplesMotion Accelerometer, gyroscopeEnvironmental Light, temperature, humidity, barometric pressureMiscellaneous Camera, microphone, fingerprint, infrared

Displaying Sensors• Display all device sensors (and

their 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

Views

RecyclerView Workflow

29Source: Figs. 8.6–8.7, Bill Phillips, Chris Stewart, and Kristin Marsicano, Android Programming: The Big Nerd Ranch Guide, 3rd ed., 2017.

Listing Available Sensors: Javaprivate RecyclerView mSensorRecyclerView;

private SensorAdapter mSensorAdapter;

private SensorManager mSensorManager;private List<Sensor> mSensorList;

@Overridepublic 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: Kotlinprivate lateinit var mSensorRecyclerView: RecyclerViewprivate lateinit var mAdapter: SensorAdapterprivate lateinit var mSensorManager: SensorManagerprivate 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 SensorManagermSensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL)mAdapter = SensorAdapter(mSensorList)mSensorRecyclerView.adapter = mAdaptermSensorRecyclerView.itemAnimator = DefaultItemAnimator()

return v}

31

Sensor HolderJava

private class SensorHolder extends

RecyclerView.ViewHolder {private Sensor mSensor;private String mDescriptionStr;

private TextView mSensorInfoTextView;

public SensorHolder(LayoutInflater inflater,

ViewGroup parent) {super(inflater.inflate(

R.layout.list_item_sensor, parent, false));

mSensorInfoTextView =

itemView.findViewById(R.id.sensor_data);}

public void bind(Sensor sensor) {mSensor = sensor;mDescriptionStr = getSensorDescription(sensor);mSensorInfoTextView.setText(mDescriptionStr);

}

}

Kotlinprivate inner class SensorHolder(

inflater: LayoutInflater, parent: ViewGroup) : RecyclerView.ViewHolder(

inflater.inflate(R.layout.list_item_sensor, parent, false)) {

private lateinit var mSensor: Sensorprivate lateinit var mDescriptionStr: Stringprivate val mSensorInfoTextView: TextView

init { mSensorInfoTextView = itemView.findViewById(R.id.sensor_data)

}

fun bind(sensor: Sensor) {mSensor = sensormDescriptionStr = getSensorDescription(

sensor)mSensorInfoTextView.text = mDescriptionStr

}}

32

Sensor AdapterJava

private class SensorAdapter extends RecyclerView.Adapter<SensorHolder> {private List<Sensor> mSensorList;public SensorAdapter(List<Sensor> sensorList) {

mSensorList = sensorList; }

@Override public SensorHolder onCreateViewHolder(

ViewGroup parent, int viewType) {LayoutInflater inflater = LayoutInflater.from(

getActivity());return new SensorHolder(inflater, parent);

}

@Overridepublic void onBindViewHolder(SensorHolder holder,

int position) {Sensor sensor = SensorsFragment.this.mSensorList

.get(position);String sensorDescription = getSensorDescription(

sensor); holder.bind(sensor);}@Overridepublic int getItemCount() {

return SensorList.size(); }}

Kotlinprivate inner class SensorAdapter(

private val mSensorList: List<Sensor>) : RecyclerView.Adapter<SensorHolder>() {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SensorHolder {val inflater = LayoutInflater.from(activity)return SensorHolder(inflater, parent)

}

override fun onBindViewHolder(holder: SensorHolder, position: Int) {val sensor = this@SensorsFragment.

mSensorList[position]holder.bind(sensor)

}

override fun getItemCount(): Int {return mSensorList.size }

}

33

Registering Sensor Updates

Java@Overridepublic void onResume() {

super.onResume(); // . . .// Start listening to sensor updatesfor (Sensor sensor : mSensorList) {

mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL);

}}

// . . .@Overridepublic void onPause() {

super.onPause();// Stop updates when pausedmSensorManager.unregisterListener(this);

}

Kotlinoverride fun onResume() {

super.onResume() // . . .// Start listening to sensor updatesfor (sensor in mSensorList) {

mSensorManager.registerListener(this, sensor,SensorManager.SENSOR_DELAY_NORMAL)

}}// . . .override fun onPause() {

super.onPause()// Stop updates when pausedmSensorManager.unregisterListener(this)

}

34

Receiving Sensor Updates

Java@Overridepublic void onSensorChanged(

SensorEvent sensorEvent) {String sensorEventString =

sensorEventToString(sensorEvent);// . . .Log.d(TAG, "--- EVENT Raw Values ---\n” +

sensorName + "\n" + "Distance Last = >” + distanceOfLastValue + "<\n" +"Distance This = >" + distanceOfThisValue + "<\n" +"Change = >" + change + "<\n" +"Percent = >" + percentageChange + "%\n" + "Last value = " + lastValueString + "<\n" +sensorEventString);

}

Kotlinoverride fun onSensorChanged(

sensorEvent: SensorEvent) {val sensorEventString =

sensorEventToString(sensorEvent)// . . .Log.d(TAG, "--- EVENT Raw Values ---\n" +

sensorName + "\nDistance Last= >" +distanceOfLastValue + "<\n" + "Distance This= >" + distanceOfThisValue + "<\n" + "Change = >" + change + "<\n" + "Percent = >" + percentageChange + "%\n" + "Last value = " + lastValueString + "<\n" + sensorEventString)

}

35See complete method for how to filter out noise.

Extracting Sensor Parameters

Javapublic String getSensorDescription(

Sensor sensor) {return "Sensor: " + sensor.getName() + "; Ver :" + sensor.getVersion() + "; Range: " + sensor.getMaximumRange() + "; Power: " + sensor.getPower() + "; Res: " + sensor.getResolution();

}

Kotlinfun getSensorDescription(

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

top related